Line data Source code
1 : //===-- WebAssemblyWasmObjectWriter.cpp - WebAssembly Wasm Writer ---------===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : ///
10 : /// \file
11 : /// This file handles Wasm-specific object emission, converting LLVM's
12 : /// internal fixups into the appropriate relocations.
13 : ///
14 : //===----------------------------------------------------------------------===//
15 :
16 : #include "MCTargetDesc/WebAssemblyFixupKinds.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/MCFixupKindInfo.h"
22 : #include "llvm/MC/MCObjectWriter.h"
23 : #include "llvm/MC/MCSectionWasm.h"
24 : #include "llvm/MC/MCSymbolWasm.h"
25 : #include "llvm/MC/MCValue.h"
26 : #include "llvm/MC/MCWasmObjectWriter.h"
27 : #include "llvm/Support/Casting.h"
28 : #include "llvm/Support/ErrorHandling.h"
29 :
30 : using namespace llvm;
31 :
32 : namespace {
33 0 : class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter {
34 : public:
35 : explicit WebAssemblyWasmObjectWriter(bool Is64Bit);
36 :
37 : private:
38 : unsigned getRelocType(const MCValue &Target,
39 : const MCFixup &Fixup) const override;
40 : };
41 : } // end anonymous namespace
42 :
43 0 : WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit)
44 0 : : MCWasmObjectTargetWriter(Is64Bit) {}
45 :
46 : // Test whether the given expression computes a function address.
47 444 : static bool IsFunctionExpr(const MCExpr *Expr) {
48 : if (auto SyExp = dyn_cast<MCSymbolRefExpr>(Expr))
49 872 : return cast<MCSymbolWasm>(SyExp->getSymbol()).isFunction();
50 :
51 : if (auto BinOp = dyn_cast<MCBinaryExpr>(Expr))
52 4 : return IsFunctionExpr(BinOp->getLHS()) != IsFunctionExpr(BinOp->getRHS());
53 :
54 : if (auto UnOp = dyn_cast<MCUnaryExpr>(Expr))
55 0 : return IsFunctionExpr(UnOp->getSubExpr());
56 :
57 : return false;
58 : }
59 :
60 : static bool IsFunctionType(const MCValue &Target) {
61 : const MCSymbolRefExpr *RefA = Target.getSymA();
62 247 : return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX;
63 : }
64 :
65 113 : static const MCSection *GetFixupSection(const MCExpr *Expr) {
66 : if (auto SyExp = dyn_cast<MCSymbolRefExpr>(Expr)) {
67 105 : if (SyExp->getSymbol().isInSection())
68 95 : return &SyExp->getSymbol().getSection();
69 : return nullptr;
70 : }
71 :
72 : if (auto BinOp = dyn_cast<MCBinaryExpr>(Expr)) {
73 4 : auto SectionLHS = GetFixupSection(BinOp->getLHS());
74 4 : auto SectionRHS = GetFixupSection(BinOp->getRHS());
75 5 : return SectionLHS == SectionRHS ? nullptr : SectionLHS;
76 : }
77 :
78 : if (auto UnOp = dyn_cast<MCUnaryExpr>(Expr))
79 0 : return GetFixupSection(UnOp->getSubExpr());
80 :
81 : return nullptr;
82 : }
83 :
84 : static bool IsGlobalType(const MCValue &Target) {
85 267 : const MCSymbolRefExpr *RefA = Target.getSymA();
86 267 : return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_GLOBAL;
87 : }
88 :
89 436 : unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
90 : const MCFixup &Fixup) const {
91 : // WebAssembly functions are not allocated in the data address space. To
92 : // resolve a pointer to a function, we must use a special relocation type.
93 436 : bool IsFunction = IsFunctionExpr(Fixup.getValue());
94 :
95 436 : switch (unsigned(Fixup.getKind())) {
96 49 : case WebAssembly::fixup_code_sleb128_i32:
97 49 : if (IsFunction)
98 27 : return wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB;
99 : return wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB;
100 : case WebAssembly::fixup_code_sleb128_i64:
101 : llvm_unreachable("fixup_sleb128_i64 not implemented yet");
102 : case WebAssembly::fixup_code_uleb128_i32:
103 : if (IsGlobalType(Target))
104 : return wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB;
105 : if (IsFunctionType(Target))
106 : return wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB;
107 236 : if (IsFunction)
108 93 : return wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB;
109 : return wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB;
110 120 : case FK_Data_4:
111 120 : if (IsFunction)
112 : return wasm::R_WEBASSEMBLY_TABLE_INDEX_I32;
113 105 : if (auto Section = static_cast<const MCSectionWasm *>(
114 105 : GetFixupSection(Fixup.getValue()))) {
115 95 : if (Section->getKind().isText())
116 : return wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32;
117 69 : else if (!Section->isWasmData())
118 58 : return wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32;
119 : }
120 : return wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32;
121 : case FK_Data_8:
122 : llvm_unreachable("FK_Data_8 not implemented yet");
123 0 : default:
124 0 : llvm_unreachable("unimplemented fixup kind");
125 : }
126 : }
127 :
128 : std::unique_ptr<MCObjectTargetWriter>
129 307 : llvm::createWebAssemblyWasmObjectWriter(bool Is64Bit) {
130 307 : return llvm::make_unique<WebAssemblyWasmObjectWriter>(Is64Bit);
131 : }
|