1 | //===- Wasm.h - Wasm object file implementation -----------------*- C++ -*-===// |
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 | // This file declares the WasmObjectFile class, which implements the ObjectFile |
10 | // interface for Wasm files. |
11 | // |
12 | // See: https://github.com/WebAssembly/design/blob/main/BinaryEncoding.md |
13 | // |
14 | //===----------------------------------------------------------------------===// |
15 | |
16 | #ifndef LLVM_OBJECT_WASM_H |
17 | #define LLVM_OBJECT_WASM_H |
18 | |
19 | #include "llvm/ADT/ArrayRef.h" |
20 | #include "llvm/ADT/StringRef.h" |
21 | #include "llvm/BinaryFormat/Wasm.h" |
22 | #include "llvm/Config/llvm-config.h" |
23 | #include "llvm/MC/MCSymbolWasm.h" |
24 | #include "llvm/Object/Binary.h" |
25 | #include "llvm/Object/ObjectFile.h" |
26 | #include "llvm/Support/Error.h" |
27 | #include "llvm/Support/MemoryBuffer.h" |
28 | #include <cstddef> |
29 | #include <cstdint> |
30 | #include <vector> |
31 | |
32 | namespace llvm { |
33 | namespace object { |
34 | |
35 | class WasmSymbol { |
36 | public: |
37 | WasmSymbol(const wasm::WasmSymbolInfo &Info, |
38 | const wasm::WasmGlobalType *GlobalType, |
39 | const wasm::WasmTableType *TableType, |
40 | const wasm::WasmSignature *Signature) |
41 | : Info(Info), GlobalType(GlobalType), TableType(TableType), |
42 | Signature(Signature) { |
43 | assert(!Signature || Signature->Kind != wasm::WasmSignature::Placeholder); |
44 | } |
45 | |
46 | // Symbol info as represented in the symbol's 'syminfo' entry of an object |
47 | // file's symbol table. |
48 | wasm::WasmSymbolInfo Info; |
49 | const wasm::WasmGlobalType *GlobalType; |
50 | const wasm::WasmTableType *TableType; |
51 | const wasm::WasmSignature *Signature; |
52 | |
53 | bool isTypeFunction() const { |
54 | return Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION; |
55 | } |
56 | |
57 | bool isTypeTable() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_TABLE; } |
58 | |
59 | bool isTypeData() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_DATA; } |
60 | |
61 | bool isTypeGlobal() const { |
62 | return Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL; |
63 | } |
64 | |
65 | bool isTypeSection() const { |
66 | return Info.Kind == wasm::WASM_SYMBOL_TYPE_SECTION; |
67 | } |
68 | |
69 | bool isTypeTag() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_TAG; } |
70 | |
71 | bool isDefined() const { return !isUndefined(); } |
72 | |
73 | bool isUndefined() const { |
74 | return (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) != 0; |
75 | } |
76 | |
77 | bool isBindingWeak() const { |
78 | return getBinding() == wasm::WASM_SYMBOL_BINDING_WEAK; |
79 | } |
80 | |
81 | bool isBindingGlobal() const { |
82 | return getBinding() == wasm::WASM_SYMBOL_BINDING_GLOBAL; |
83 | } |
84 | |
85 | bool isBindingLocal() const { |
86 | return getBinding() == wasm::WASM_SYMBOL_BINDING_LOCAL; |
87 | } |
88 | |
89 | unsigned getBinding() const { |
90 | return Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK; |
91 | } |
92 | |
93 | bool isHidden() const { |
94 | return getVisibility() == wasm::WASM_SYMBOL_VISIBILITY_HIDDEN; |
95 | } |
96 | |
97 | unsigned getVisibility() const { |
98 | return Info.Flags & wasm::WASM_SYMBOL_VISIBILITY_MASK; |
99 | } |
100 | |
101 | void print(raw_ostream &Out) const; |
102 | |
103 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
104 | LLVM_DUMP_METHOD void dump() const; |
105 | #endif |
106 | }; |
107 | |
108 | struct WasmSection { |
109 | WasmSection() = default; |
110 | |
111 | uint32_t Type = 0; |
112 | uint32_t Offset = 0; // Offset within the file |
113 | StringRef Name; // Section name (User-defined sections only) |
114 | uint32_t Comdat = UINT32_MAX; // From the "comdat info" section |
115 | ArrayRef<uint8_t> Content; |
116 | std::vector<wasm::WasmRelocation> Relocations; |
117 | // Length of the LEB encoding of the section header's size field |
118 | std::optional<uint8_t> ; |
119 | }; |
120 | |
121 | struct WasmSegment { |
122 | uint32_t SectionOffset; |
123 | wasm::WasmDataSegment Data; |
124 | }; |
125 | |
126 | class WasmObjectFile : public ObjectFile { |
127 | |
128 | public: |
129 | WasmObjectFile(MemoryBufferRef Object, Error &Err); |
130 | |
131 | const wasm::WasmObjectHeader &() const; |
132 | const WasmSymbol &getWasmSymbol(const DataRefImpl &Symb) const; |
133 | const WasmSymbol &getWasmSymbol(const SymbolRef &Symbol) const; |
134 | const WasmSection &getWasmSection(const SectionRef &Section) const; |
135 | const wasm::WasmRelocation &getWasmRelocation(const RelocationRef &Ref) const; |
136 | |
137 | static bool classof(const Binary *v) { return v->isWasm(); } |
138 | |
139 | const wasm::WasmDylinkInfo &dylinkInfo() const { return DylinkInfo; } |
140 | const wasm::WasmProducerInfo &getProducerInfo() const { return ProducerInfo; } |
141 | ArrayRef<wasm::WasmFeatureEntry> getTargetFeatures() const { |
142 | return TargetFeatures; |
143 | } |
144 | ArrayRef<wasm::WasmSignature> types() const { return Signatures; } |
145 | ArrayRef<wasm::WasmImport> imports() const { return Imports; } |
146 | ArrayRef<wasm::WasmTable> tables() const { return Tables; } |
147 | ArrayRef<wasm::WasmLimits> memories() const { return Memories; } |
148 | ArrayRef<wasm::WasmGlobal> globals() const { return Globals; } |
149 | ArrayRef<wasm::WasmTag> tags() const { return Tags; } |
150 | ArrayRef<wasm::WasmExport> exports() const { return Exports; } |
151 | const wasm::WasmLinkingData &linkingData() const { return LinkingData; } |
152 | uint32_t getNumberOfSymbols() const { return Symbols.size(); } |
153 | ArrayRef<wasm::WasmElemSegment> elements() const { return ElemSegments; } |
154 | ArrayRef<WasmSegment> dataSegments() const { return DataSegments; } |
155 | ArrayRef<wasm::WasmFunction> functions() const { return Functions; } |
156 | ArrayRef<wasm::WasmDebugName> debugNames() const { return DebugNames; } |
157 | uint32_t startFunction() const { return StartFunction; } |
158 | uint32_t getNumImportedGlobals() const { return NumImportedGlobals; } |
159 | uint32_t getNumImportedTables() const { return NumImportedTables; } |
160 | uint32_t getNumImportedFunctions() const { return NumImportedFunctions; } |
161 | uint32_t getNumImportedTags() const { return NumImportedTags; } |
162 | uint32_t getNumSections() const { return Sections.size(); } |
163 | void moveSymbolNext(DataRefImpl &Symb) const override; |
164 | |
165 | Expected<uint32_t> getSymbolFlags(DataRefImpl Symb) const override; |
166 | |
167 | basic_symbol_iterator symbol_begin() const override; |
168 | |
169 | basic_symbol_iterator symbol_end() const override; |
170 | Expected<StringRef> getSymbolName(DataRefImpl Symb) const override; |
171 | |
172 | bool is64Bit() const override { return false; } |
173 | |
174 | Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; |
175 | uint64_t getWasmSymbolValue(const WasmSymbol &Sym) const; |
176 | uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; |
177 | uint32_t getSymbolAlignment(DataRefImpl Symb) const override; |
178 | uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; |
179 | Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override; |
180 | Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override; |
181 | uint32_t getSymbolSectionId(SymbolRef Sym) const; |
182 | uint32_t getSymbolSize(SymbolRef Sym) const; |
183 | |
184 | // Overrides from SectionRef. |
185 | void moveSectionNext(DataRefImpl &Sec) const override; |
186 | Expected<StringRef> getSectionName(DataRefImpl Sec) const override; |
187 | uint64_t getSectionAddress(DataRefImpl Sec) const override; |
188 | uint64_t getSectionIndex(DataRefImpl Sec) const override; |
189 | uint64_t getSectionSize(DataRefImpl Sec) const override; |
190 | Expected<ArrayRef<uint8_t>> |
191 | getSectionContents(DataRefImpl Sec) const override; |
192 | uint64_t getSectionAlignment(DataRefImpl Sec) const override; |
193 | bool isSectionCompressed(DataRefImpl Sec) const override; |
194 | bool isSectionText(DataRefImpl Sec) const override; |
195 | bool isSectionData(DataRefImpl Sec) const override; |
196 | bool isSectionBSS(DataRefImpl Sec) const override; |
197 | bool isSectionVirtual(DataRefImpl Sec) const override; |
198 | relocation_iterator section_rel_begin(DataRefImpl Sec) const override; |
199 | relocation_iterator section_rel_end(DataRefImpl Sec) const override; |
200 | |
201 | // Overrides from RelocationRef. |
202 | void moveRelocationNext(DataRefImpl &Rel) const override; |
203 | uint64_t getRelocationOffset(DataRefImpl Rel) const override; |
204 | symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override; |
205 | uint64_t getRelocationType(DataRefImpl Rel) const override; |
206 | void getRelocationTypeName(DataRefImpl Rel, |
207 | SmallVectorImpl<char> &Result) const override; |
208 | |
209 | section_iterator section_begin() const override; |
210 | section_iterator section_end() const override; |
211 | uint8_t getBytesInAddress() const override; |
212 | StringRef getFileFormatName() const override; |
213 | Triple::ArchType getArch() const override; |
214 | Expected<SubtargetFeatures> getFeatures() const override; |
215 | bool isRelocatableObject() const override; |
216 | bool isSharedObject() const; |
217 | bool hasUnmodeledTypes() const { return HasUnmodeledTypes; } |
218 | |
219 | struct ReadContext { |
220 | const uint8_t *Start; |
221 | const uint8_t *Ptr; |
222 | const uint8_t *End; |
223 | }; |
224 | |
225 | private: |
226 | bool isValidFunctionIndex(uint32_t Index) const; |
227 | bool isDefinedFunctionIndex(uint32_t Index) const; |
228 | bool isValidGlobalIndex(uint32_t Index) const; |
229 | bool isValidTableNumber(uint32_t Index) const; |
230 | bool isDefinedGlobalIndex(uint32_t Index) const; |
231 | bool isDefinedTableNumber(uint32_t Index) const; |
232 | bool isValidTagIndex(uint32_t Index) const; |
233 | bool isDefinedTagIndex(uint32_t Index) const; |
234 | bool isValidFunctionSymbol(uint32_t Index) const; |
235 | bool isValidTableSymbol(uint32_t Index) const; |
236 | bool isValidGlobalSymbol(uint32_t Index) const; |
237 | bool isValidTagSymbol(uint32_t Index) const; |
238 | bool isValidDataSymbol(uint32_t Index) const; |
239 | bool isValidSectionSymbol(uint32_t Index) const; |
240 | wasm::WasmFunction &getDefinedFunction(uint32_t Index); |
241 | const wasm::WasmFunction &getDefinedFunction(uint32_t Index) const; |
242 | const wasm::WasmGlobal &getDefinedGlobal(uint32_t Index) const; |
243 | wasm::WasmTag &getDefinedTag(uint32_t Index); |
244 | |
245 | const WasmSection &getWasmSection(DataRefImpl Ref) const; |
246 | const wasm::WasmRelocation &getWasmRelocation(DataRefImpl Ref) const; |
247 | uint32_t getSymbolSectionIdImpl(const WasmSymbol &Symb) const; |
248 | |
249 | Error parseSection(WasmSection &Sec); |
250 | Error parseCustomSection(WasmSection &Sec, ReadContext &Ctx); |
251 | |
252 | // Standard section types |
253 | Error parseTypeSection(ReadContext &Ctx); |
254 | Error parseImportSection(ReadContext &Ctx); |
255 | Error parseFunctionSection(ReadContext &Ctx); |
256 | Error parseTableSection(ReadContext &Ctx); |
257 | Error parseMemorySection(ReadContext &Ctx); |
258 | Error parseTagSection(ReadContext &Ctx); |
259 | Error parseGlobalSection(ReadContext &Ctx); |
260 | Error parseExportSection(ReadContext &Ctx); |
261 | Error parseStartSection(ReadContext &Ctx); |
262 | Error parseElemSection(ReadContext &Ctx); |
263 | Error parseCodeSection(ReadContext &Ctx); |
264 | Error parseDataSection(ReadContext &Ctx); |
265 | Error parseDataCountSection(ReadContext &Ctx); |
266 | |
267 | // Custom section types |
268 | Error parseDylinkSection(ReadContext &Ctx); |
269 | Error parseDylink0Section(ReadContext &Ctx); |
270 | Error parseNameSection(ReadContext &Ctx); |
271 | Error parseLinkingSection(ReadContext &Ctx); |
272 | Error parseLinkingSectionSymtab(ReadContext &Ctx); |
273 | Error parseLinkingSectionComdat(ReadContext &Ctx); |
274 | Error (ReadContext &Ctx); |
275 | Error parseTargetFeaturesSection(ReadContext &Ctx); |
276 | Error parseRelocSection(StringRef Name, ReadContext &Ctx); |
277 | |
278 | wasm::WasmObjectHeader ; |
279 | std::vector<WasmSection> Sections; |
280 | wasm::WasmDylinkInfo DylinkInfo; |
281 | wasm::WasmProducerInfo ProducerInfo; |
282 | std::vector<wasm::WasmFeatureEntry> TargetFeatures; |
283 | std::vector<wasm::WasmSignature> Signatures; |
284 | std::vector<wasm::WasmTable> Tables; |
285 | std::vector<wasm::WasmLimits> Memories; |
286 | std::vector<wasm::WasmGlobal> Globals; |
287 | std::vector<wasm::WasmTag> Tags; |
288 | std::vector<wasm::WasmImport> Imports; |
289 | std::vector<wasm::WasmExport> Exports; |
290 | std::vector<wasm::WasmElemSegment> ElemSegments; |
291 | std::vector<WasmSegment> DataSegments; |
292 | std::optional<size_t> DataCount; |
293 | std::vector<wasm::WasmFunction> Functions; |
294 | std::vector<WasmSymbol> Symbols; |
295 | std::vector<wasm::WasmDebugName> DebugNames; |
296 | uint32_t StartFunction = -1; |
297 | bool HasLinkingSection = false; |
298 | bool HasDylinkSection = false; |
299 | bool HasMemory64 = false; |
300 | bool HasUnmodeledTypes = false; |
301 | wasm::WasmLinkingData LinkingData; |
302 | uint32_t NumImportedGlobals = 0; |
303 | uint32_t NumImportedTables = 0; |
304 | uint32_t NumImportedFunctions = 0; |
305 | uint32_t NumImportedTags = 0; |
306 | uint32_t CodeSection = 0; |
307 | uint32_t DataSection = 0; |
308 | uint32_t TagSection = 0; |
309 | uint32_t GlobalSection = 0; |
310 | uint32_t TableSection = 0; |
311 | }; |
312 | |
313 | class WasmSectionOrderChecker { |
314 | public: |
315 | // We define orders for all core wasm sections and known custom sections. |
316 | enum : int { |
317 | // Sentinel, must be zero |
318 | WASM_SEC_ORDER_NONE = 0, |
319 | |
320 | // Core sections |
321 | WASM_SEC_ORDER_TYPE, |
322 | WASM_SEC_ORDER_IMPORT, |
323 | WASM_SEC_ORDER_FUNCTION, |
324 | WASM_SEC_ORDER_TABLE, |
325 | WASM_SEC_ORDER_MEMORY, |
326 | WASM_SEC_ORDER_TAG, |
327 | WASM_SEC_ORDER_GLOBAL, |
328 | WASM_SEC_ORDER_EXPORT, |
329 | WASM_SEC_ORDER_START, |
330 | WASM_SEC_ORDER_ELEM, |
331 | WASM_SEC_ORDER_DATACOUNT, |
332 | WASM_SEC_ORDER_CODE, |
333 | WASM_SEC_ORDER_DATA, |
334 | |
335 | // Custom sections |
336 | // "dylink" should be the very first section in the module |
337 | WASM_SEC_ORDER_DYLINK, |
338 | // "linking" section requires DATA section in order to validate data symbols |
339 | WASM_SEC_ORDER_LINKING, |
340 | // Must come after "linking" section in order to validate reloc indexes. |
341 | WASM_SEC_ORDER_RELOC, |
342 | // "name" section must appear after DATA. Comes after "linking" to allow |
343 | // symbol table to set default function name. |
344 | WASM_SEC_ORDER_NAME, |
345 | // "producers" section must appear after "name" section. |
346 | WASM_SEC_ORDER_PRODUCERS, |
347 | // "target_features" section must appear after producers section |
348 | WASM_SEC_ORDER_TARGET_FEATURES, |
349 | |
350 | // Must be last |
351 | WASM_NUM_SEC_ORDERS |
352 | |
353 | }; |
354 | |
355 | // Sections that may or may not be present, but cannot be predecessors |
356 | static int DisallowedPredecessors[WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS]; |
357 | |
358 | bool isValidSectionOrder(unsigned ID, StringRef CustomSectionName = "" ); |
359 | |
360 | private: |
361 | bool Seen[WASM_NUM_SEC_ORDERS] = {}; // Sections that have been seen already |
362 | |
363 | // Returns -1 for unknown sections. |
364 | int getSectionOrder(unsigned ID, StringRef CustomSectionName = "" ); |
365 | }; |
366 | |
367 | } // end namespace object |
368 | |
369 | inline raw_ostream &operator<<(raw_ostream &OS, const object::WasmSymbol &Sym) { |
370 | Sym.print(Out&: OS); |
371 | return OS; |
372 | } |
373 | |
374 | } // end namespace llvm |
375 | |
376 | #endif // LLVM_OBJECT_WASM_H |
377 | |