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/WebAssemblyMCAsmInfo.h" |
17 | #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" |
18 | #include "llvm/BinaryFormat/Wasm.h" |
19 | #include "llvm/MC/MCAsmBackend.h" |
20 | #include "llvm/MC/MCFixup.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 | auto &SymA = cast<MCSymbolWasm>(Val: *Target.getAddSym()); |
70 | auto Spec = WebAssembly::Specifier(Target.getSpecifier()); |
71 | switch (Spec) { |
72 | case WebAssembly::S_GOT: |
73 | SymA.setUsedInGOT(); |
74 | return wasm::R_WASM_GLOBAL_INDEX_LEB; |
75 | case WebAssembly::S_GOT_TLS: |
76 | SymA.setUsedInGOT(); |
77 | SymA.setTLS(); |
78 | return wasm::R_WASM_GLOBAL_INDEX_LEB; |
79 | case WebAssembly::S_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 WebAssembly::S_TLSREL: |
84 | SymA.setTLS(); |
85 | return is64Bit() ? wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64 |
86 | : wasm::R_WASM_MEMORY_ADDR_TLS_SLEB; |
87 | case WebAssembly::S_MBREL: |
88 | assert(SymA.isData()); |
89 | return is64Bit() ? wasm::R_WASM_MEMORY_ADDR_REL_SLEB64 |
90 | : wasm::R_WASM_MEMORY_ADDR_REL_SLEB; |
91 | case WebAssembly::S_TYPEINDEX: |
92 | return wasm::R_WASM_TYPE_INDEX_LEB; |
93 | case WebAssembly::S_None: |
94 | break; |
95 | case WebAssembly::S_FUNCINDEX: |
96 | return wasm::R_WASM_FUNCTION_INDEX_I32; |
97 | } |
98 | |
99 | switch (unsigned(Fixup.getKind())) { |
100 | case WebAssembly::fixup_sleb128_i32: |
101 | if (SymA.isFunction()) |
102 | return wasm::R_WASM_TABLE_INDEX_SLEB; |
103 | return wasm::R_WASM_MEMORY_ADDR_SLEB; |
104 | case WebAssembly::fixup_sleb128_i64: |
105 | if (SymA.isFunction()) |
106 | return wasm::R_WASM_TABLE_INDEX_SLEB64; |
107 | return wasm::R_WASM_MEMORY_ADDR_SLEB64; |
108 | case WebAssembly::fixup_uleb128_i32: |
109 | if (SymA.isGlobal()) |
110 | return wasm::R_WASM_GLOBAL_INDEX_LEB; |
111 | if (SymA.isFunction()) |
112 | return wasm::R_WASM_FUNCTION_INDEX_LEB; |
113 | if (SymA.isTag()) |
114 | return wasm::R_WASM_TAG_INDEX_LEB; |
115 | if (SymA.isTable()) |
116 | return wasm::R_WASM_TABLE_NUMBER_LEB; |
117 | return wasm::R_WASM_MEMORY_ADDR_LEB; |
118 | case WebAssembly::fixup_uleb128_i64: |
119 | assert(SymA.isData()); |
120 | return wasm::R_WASM_MEMORY_ADDR_LEB64; |
121 | case FK_Data_4: |
122 | if (SymA.isFunction()) { |
123 | if (FixupSection.isMetadata()) |
124 | return wasm::R_WASM_FUNCTION_OFFSET_I32; |
125 | assert(FixupSection.isWasmData()); |
126 | return wasm::R_WASM_TABLE_INDEX_I32; |
127 | } |
128 | if (SymA.isGlobal()) |
129 | return wasm::R_WASM_GLOBAL_INDEX_I32; |
130 | if (auto Section = static_cast<const MCSectionWasm *>( |
131 | getTargetSection(Expr: Fixup.getValue()))) { |
132 | if (Section->isText()) |
133 | return wasm::R_WASM_FUNCTION_OFFSET_I32; |
134 | else if (!Section->isWasmData()) |
135 | return wasm::R_WASM_SECTION_OFFSET_I32; |
136 | } |
137 | return IsLocRel ? wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 |
138 | : wasm::R_WASM_MEMORY_ADDR_I32; |
139 | case FK_Data_8: |
140 | if (SymA.isFunction()) { |
141 | if (FixupSection.isMetadata()) |
142 | return wasm::R_WASM_FUNCTION_OFFSET_I64; |
143 | return wasm::R_WASM_TABLE_INDEX_I64; |
144 | } |
145 | if (SymA.isGlobal()) |
146 | llvm_unreachable("unimplemented R_WASM_GLOBAL_INDEX_I64" ); |
147 | if (auto Section = static_cast<const MCSectionWasm *>( |
148 | getTargetSection(Expr: Fixup.getValue()))) { |
149 | if (Section->isText()) |
150 | return wasm::R_WASM_FUNCTION_OFFSET_I64; |
151 | else if (!Section->isWasmData()) |
152 | llvm_unreachable("unimplemented R_WASM_SECTION_OFFSET_I64" ); |
153 | } |
154 | assert(SymA.isData()); |
155 | return wasm::R_WASM_MEMORY_ADDR_I64; |
156 | default: |
157 | llvm_unreachable("unimplemented fixup kind" ); |
158 | } |
159 | } |
160 | |
161 | std::unique_ptr<MCObjectTargetWriter> |
162 | llvm::createWebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten) { |
163 | return std::make_unique<WebAssemblyWasmObjectWriter>(args&: Is64Bit, args&: IsEmscripten); |
164 | } |
165 | |