Bug Summary

File:tools/lld/wasm/InputChunks.h
Warning:line 169, column 12
Access to field 'CodeSection' results in a dereference of a null pointer (loaded from field 'File')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name InputChunks.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-8/lib/clang/8.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lld/wasm -I /build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm -I /build/llvm-toolchain-snapshot-8~svn345461/tools/lld/include -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lld/include -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/include -I /build/llvm-toolchain-snapshot-8~svn345461/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/backward -internal-isystem /usr/include/clang/8.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-8/lib/clang/8.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lld/wasm -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-10-27-211344-32123-1 -x c++ /build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp -faddrsig

/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp

1//===- InputChunks.cpp ----------------------------------------------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "InputChunks.h"
11#include "Config.h"
12#include "OutputSegment.h"
13#include "WriterUtils.h"
14#include "lld/Common/ErrorHandler.h"
15#include "lld/Common/LLVM.h"
16#include "llvm/Support/LEB128.h"
17
18#define DEBUG_TYPE"lld" "lld"
19
20using namespace llvm;
21using namespace llvm::wasm;
22using namespace llvm::support::endian;
23using namespace lld;
24using namespace lld::wasm;
25
26static StringRef ReloctTypeToString(uint8_t RelocType) {
27 switch (RelocType) {
28#define WASM_RELOC(NAME, REL) \
29 case REL: \
30 return #NAME;
31#include "llvm/BinaryFormat/WasmRelocs.def"
32#undef WASM_RELOC
33 }
34 llvm_unreachable("unknown reloc type")::llvm::llvm_unreachable_internal("unknown reloc type", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp"
, 34)
;
35}
36
37std::string lld::toString(const InputChunk *C) {
38 return (toString(C->File) + ":(" + C->getName() + ")").str();
39}
40
41StringRef InputChunk::getComdatName() const {
42 uint32_t Index = getComdat();
43 if (Index == UINT32_MAX(4294967295U))
44 return StringRef();
45 return File->getWasmObj()->linkingData().Comdats[Index];
46}
47
48void InputChunk::verifyRelocTargets() const {
49 for (const WasmRelocation &Rel : Relocations) {
50 uint32_t ExistingValue;
51 unsigned BytesRead = 0;
52 uint32_t Offset = Rel.Offset - getInputSectionOffset();
53 const uint8_t *Loc = data().data() + Offset;
54 switch (Rel.Type) {
55 case R_WEBASSEMBLY_TYPE_INDEX_LEB:
56 case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
57 case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
58 case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
59 ExistingValue = decodeULEB128(Loc, &BytesRead);
60 break;
61 case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
62 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
63 ExistingValue = static_cast<uint32_t>(decodeSLEB128(Loc, &BytesRead));
64 break;
65 case R_WEBASSEMBLY_TABLE_INDEX_I32:
66 case R_WEBASSEMBLY_MEMORY_ADDR_I32:
67 case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
68 case R_WEBASSEMBLY_SECTION_OFFSET_I32:
69 ExistingValue = static_cast<uint32_t>(read32le(Loc));
70 break;
71 default:
72 llvm_unreachable("unknown relocation type")::llvm::llvm_unreachable_internal("unknown relocation type", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp"
, 72)
;
73 }
74
75 if (BytesRead && BytesRead != 5)
76 warn("expected LEB at relocation site be 5-byte padded");
77 uint32_t ExpectedValue = File->calcExpectedValue(Rel);
78 if (ExpectedValue != ExistingValue)
79 warn("unexpected existing value for " + ReloctTypeToString(Rel.Type) +
80 ": existing=" + Twine(ExistingValue) +
81 " expected=" + Twine(ExpectedValue));
82 }
83}
84
85// Copy this input chunk to an mmap'ed output file and apply relocations.
86void InputChunk::writeTo(uint8_t *Buf) const {
87 // Copy contents
88 memcpy(Buf + OutputOffset, data().data(), data().size());
3
Calling 'InputFunction::data'
89
90 // Apply relocations
91 if (Relocations.empty())
92 return;
93
94#ifndef NDEBUG
95 verifyRelocTargets();
96#endif
97
98 LLVM_DEBUG(dbgs() << "applying relocations: " << getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "applying relocations: " << getName
() << " count=" << Relocations.size() << "\n"
; } } while (false)
99 << " count=" << Relocations.size() << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "applying relocations: " << getName
() << " count=" << Relocations.size() << "\n"
; } } while (false)
;
100 int32_t Off = OutputOffset - getInputSectionOffset();
101
102 for (const WasmRelocation &Rel : Relocations) {
103 uint8_t *Loc = Buf + Rel.Offset + Off;
104 uint32_t Value = File->calcNewValue(Rel);
105 LLVM_DEBUG(dbgs() << "apply reloc: type=" << ReloctTypeToString(Rel.Type)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "apply reloc: type=" << ReloctTypeToString
(Rel.Type) << " addend=" << Rel.Addend << " index="
<< Rel.Index << " value=" << Value <<
" offset=" << Rel.Offset << "\n"; } } while (false
)
106 << " addend=" << Rel.Addend << " index=" << Rel.Indexdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "apply reloc: type=" << ReloctTypeToString
(Rel.Type) << " addend=" << Rel.Addend << " index="
<< Rel.Index << " value=" << Value <<
" offset=" << Rel.Offset << "\n"; } } while (false
)
107 << " value=" << Value << " offset=" << Rel.Offsetdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "apply reloc: type=" << ReloctTypeToString
(Rel.Type) << " addend=" << Rel.Addend << " index="
<< Rel.Index << " value=" << Value <<
" offset=" << Rel.Offset << "\n"; } } while (false
)
108 << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "apply reloc: type=" << ReloctTypeToString
(Rel.Type) << " addend=" << Rel.Addend << " index="
<< Rel.Index << " value=" << Value <<
" offset=" << Rel.Offset << "\n"; } } while (false
)
;
109
110 switch (Rel.Type) {
111 case R_WEBASSEMBLY_TYPE_INDEX_LEB:
112 case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
113 case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
114 case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
115 encodeULEB128(Value, Loc, 5);
116 break;
117 case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
118 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
119 encodeSLEB128(static_cast<int32_t>(Value), Loc, 5);
120 break;
121 case R_WEBASSEMBLY_TABLE_INDEX_I32:
122 case R_WEBASSEMBLY_MEMORY_ADDR_I32:
123 case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
124 case R_WEBASSEMBLY_SECTION_OFFSET_I32:
125 write32le(Loc, Value);
126 break;
127 default:
128 llvm_unreachable("unknown relocation type")::llvm::llvm_unreachable_internal("unknown relocation type", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp"
, 128)
;
129 }
130 }
131}
132
133// Copy relocation entries to a given output stream.
134// This function is used only when a user passes "-r". For a regular link,
135// we consume relocations instead of copying them to an output file.
136void InputChunk::writeRelocations(raw_ostream &OS) const {
137 if (Relocations.empty())
138 return;
139
140 int32_t Off = OutputOffset - getInputSectionOffset();
141 LLVM_DEBUG(dbgs() << "writeRelocations: " << File->getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "writeRelocations: " << File
->getName() << " offset=" << Twine(Off) <<
"\n"; } } while (false)
142 << " offset=" << Twine(Off) << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "writeRelocations: " << File
->getName() << " offset=" << Twine(Off) <<
"\n"; } } while (false)
;
143
144 for (const WasmRelocation &Rel : Relocations) {
145 writeUleb128(OS, Rel.Type, "reloc type");
146 writeUleb128(OS, Rel.Offset + Off, "reloc offset");
147 writeUleb128(OS, File->calcNewIndex(Rel), "reloc index");
148
149 switch (Rel.Type) {
150 case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
151 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
152 case R_WEBASSEMBLY_MEMORY_ADDR_I32:
153 case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
154 case R_WEBASSEMBLY_SECTION_OFFSET_I32:
155 writeSleb128(OS, File->calcNewAddend(Rel), "reloc addend");
156 break;
157 }
158 }
159}
160
161void InputFunction::setFunctionIndex(uint32_t Index) {
162 LLVM_DEBUG(dbgs() << "InputFunction::setFunctionIndex: " << getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "InputFunction::setFunctionIndex: "
<< getName() << " -> " << Index <<
"\n"; } } while (false)
163 << " -> " << Index << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "InputFunction::setFunctionIndex: "
<< getName() << " -> " << Index <<
"\n"; } } while (false)
;
164 assert(!hasFunctionIndex())((!hasFunctionIndex()) ? static_cast<void> (0) : __assert_fail
("!hasFunctionIndex()", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp"
, 164, __PRETTY_FUNCTION__))
;
165 FunctionIndex = Index;
166}
167
168void InputFunction::setTableIndex(uint32_t Index) {
169 LLVM_DEBUG(dbgs() << "InputFunction::setTableIndex: " << getName() << " -> "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "InputFunction::setTableIndex: " <<
getName() << " -> " << Index << "\n"; }
} while (false)
170 << Index << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "InputFunction::setTableIndex: " <<
getName() << " -> " << Index << "\n"; }
} while (false)
;
171 assert(!hasTableIndex())((!hasTableIndex()) ? static_cast<void> (0) : __assert_fail
("!hasTableIndex()", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp"
, 171, __PRETTY_FUNCTION__))
;
172 TableIndex = Index;
173}
174
175// Write a relocation value without padding and return the number of bytes
176// witten.
177static unsigned writeCompressedReloc(uint8_t *Buf, const WasmRelocation &Rel,
178 uint32_t Value) {
179 switch (Rel.Type) {
180 case R_WEBASSEMBLY_TYPE_INDEX_LEB:
181 case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
182 case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
183 case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
184 return encodeULEB128(Value, Buf);
185 case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
186 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
187 return encodeSLEB128(static_cast<int32_t>(Value), Buf);
188 default:
189 llvm_unreachable("unexpected relocation type")::llvm::llvm_unreachable_internal("unexpected relocation type"
, "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp"
, 189)
;
190 }
191}
192
193static unsigned getRelocWidthPadded(const WasmRelocation &Rel) {
194 switch (Rel.Type) {
195 case R_WEBASSEMBLY_TYPE_INDEX_LEB:
196 case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
197 case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
198 case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
199 case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
200 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
201 return 5;
202 default:
203 llvm_unreachable("unexpected relocation type")::llvm::llvm_unreachable_internal("unexpected relocation type"
, "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp"
, 203)
;
204 }
205}
206
207static unsigned getRelocWidth(const WasmRelocation &Rel, uint32_t Value) {
208 uint8_t Buf[5];
209 return writeCompressedReloc(Buf, Rel, Value);
210}
211
212// Relocations of type LEB and SLEB in the code section are padded to 5 bytes
213// so that a fast linker can blindly overwrite them without needing to worry
214// about the number of bytes needed to encode the values.
215// However, for optimal output the code section can be compressed to remove
216// the padding then outputting non-relocatable files.
217// In this case we need to perform a size calculation based on the value at each
218// relocation. At best we end up saving 4 bytes for each relocation entry.
219//
220// This function only computes the final output size. It must be called
221// before getSize() is used to calculate of layout of the code section.
222void InputFunction::calculateSize() {
223 if (!File || !Config->CompressRelocations)
224 return;
225
226 LLVM_DEBUG(dbgs() << "calculateSize: " << getName() << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "calculateSize: " << getName
() << "\n"; } } while (false)
;
227
228 const uint8_t *SecStart = File->CodeSection->Content.data();
229 const uint8_t *FuncStart = SecStart + getInputSectionOffset();
230 uint32_t FunctionSizeLength;
231 decodeULEB128(FuncStart, &FunctionSizeLength);
232
233 uint32_t Start = getInputSectionOffset();
234 uint32_t End = Start + Function->Size;
235
236 uint32_t LastRelocEnd = Start + FunctionSizeLength;
237 for (const WasmRelocation &Rel : Relocations) {
238 LLVM_DEBUG(dbgs() << " region: " << (Rel.Offset - LastRelocEnd) << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << " region: " << (Rel.Offset -
LastRelocEnd) << "\n"; } } while (false)
;
239 CompressedFuncSize += Rel.Offset - LastRelocEnd;
240 CompressedFuncSize += getRelocWidth(Rel, File->calcNewValue(Rel));
241 LastRelocEnd = Rel.Offset + getRelocWidthPadded(Rel);
242 }
243 LLVM_DEBUG(dbgs() << " final region: " << (End - LastRelocEnd) << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << " final region: " << (End -
LastRelocEnd) << "\n"; } } while (false)
;
244 CompressedFuncSize += End - LastRelocEnd;
245
246 // Now we know how long the resulting function is we can add the encoding
247 // of its length
248 uint8_t Buf[5];
249 CompressedSize = CompressedFuncSize + encodeULEB128(CompressedFuncSize, Buf);
250
251 LLVM_DEBUG(dbgs() << " calculateSize orig: " << Function->Size << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << " calculateSize orig: " << Function
->Size << "\n"; } } while (false)
;
252 LLVM_DEBUG(dbgs() << " calculateSize new: " << CompressedSize << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << " calculateSize new: " << CompressedSize
<< "\n"; } } while (false)
;
253}
254
255// Override the default writeTo method so that we can (optionally) write the
256// compressed version of the function.
257void InputFunction::writeTo(uint8_t *Buf) const {
258 if (!File || !Config->CompressRelocations)
1
Assuming pointer value is null
259 return InputChunk::writeTo(Buf);
2
Calling 'InputChunk::writeTo'
260
261 Buf += OutputOffset;
262 uint8_t *Orig = Buf;
263 (void)Orig;
264
265 const uint8_t *SecStart = File->CodeSection->Content.data();
266 const uint8_t *FuncStart = SecStart + getInputSectionOffset();
267 const uint8_t *End = FuncStart + Function->Size;
268 uint32_t Count;
269 decodeULEB128(FuncStart, &Count);
270 FuncStart += Count;
271
272 LLVM_DEBUG(dbgs() << "write func: " << getName() << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << "write func: " << getName() <<
"\n"; } } while (false)
;
273 Buf += encodeULEB128(CompressedFuncSize, Buf);
274 const uint8_t *LastRelocEnd = FuncStart;
275 for (const WasmRelocation &Rel : Relocations) {
276 unsigned ChunkSize = (SecStart + Rel.Offset) - LastRelocEnd;
277 LLVM_DEBUG(dbgs() << " write chunk: " << ChunkSize << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << " write chunk: " << ChunkSize
<< "\n"; } } while (false)
;
278 memcpy(Buf, LastRelocEnd, ChunkSize);
279 Buf += ChunkSize;
280 Buf += writeCompressedReloc(Buf, Rel, File->calcNewValue(Rel));
281 LastRelocEnd = SecStart + Rel.Offset + getRelocWidthPadded(Rel);
282 }
283
284 unsigned ChunkSize = End - LastRelocEnd;
285 LLVM_DEBUG(dbgs() << " write final chunk: " << ChunkSize << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << " write final chunk: " << ChunkSize
<< "\n"; } } while (false)
;
286 memcpy(Buf, LastRelocEnd, ChunkSize);
287 LLVM_DEBUG(dbgs() << " total: " << (Buf + ChunkSize - Orig) << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("lld")) { dbgs() << " total: " << (Buf + ChunkSize
- Orig) << "\n"; } } while (false)
;
288}

/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.h

1//===- InputChunks.h --------------------------------------------*- C++ -*-===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// An InputChunks represents an indivisible opaque region of a input wasm file.
11// i.e. a single wasm data segment or a single wasm function.
12//
13// They are written directly to the mmap'd output file after which relocations
14// are applied. Because each Chunk is independent they can be written in
15// parallel.
16//
17// Chunks are also unit on which garbage collection (--gc-sections) operates.
18//
19//===----------------------------------------------------------------------===//
20
21#ifndef LLD_WASM_INPUT_CHUNKS_H
22#define LLD_WASM_INPUT_CHUNKS_H
23
24#include "Config.h"
25#include "InputFiles.h"
26#include "lld/Common/ErrorHandler.h"
27#include "llvm/Object/Wasm.h"
28
29using llvm::object::WasmSection;
30using llvm::object::WasmSegment;
31using llvm::wasm::WasmFunction;
32using llvm::wasm::WasmRelocation;
33using llvm::wasm::WasmSignature;
34
35namespace llvm {
36class raw_ostream;
37}
38
39namespace lld {
40namespace wasm {
41
42class ObjFile;
43class OutputSegment;
44
45class InputChunk {
46public:
47 enum Kind { DataSegment, Function, SyntheticFunction, Section };
48
49 Kind kind() const { return SectionKind; }
50
51 virtual uint32_t getSize() const { return data().size(); }
52 virtual uint32_t getInputSize() const { return getSize(); };
53
54 virtual void writeTo(uint8_t *SectionStart) const;
55
56 ArrayRef<WasmRelocation> getRelocations() const { return Relocations; }
57 void setRelocations(ArrayRef<WasmRelocation> Rs) { Relocations = Rs; }
58
59 virtual StringRef getName() const = 0;
60 virtual StringRef getDebugName() const = 0;
61 virtual uint32_t getComdat() const = 0;
62 StringRef getComdatName() const;
63 virtual uint32_t getInputSectionOffset() const = 0;
64
65 size_t NumRelocations() const { return Relocations.size(); }
66 void writeRelocations(llvm::raw_ostream &OS) const;
67
68 ObjFile *File;
69 int32_t OutputOffset = 0;
70
71 // Signals that the section is part of the output. The garbage collector,
72 // and COMDAT handling can set a sections' Live bit.
73 // If GC is disabled, all sections start out as live by default.
74 unsigned Live : 1;
75
76protected:
77 InputChunk(ObjFile *F, Kind K)
78 : File(F), Live(!Config->GcSections), SectionKind(K) {}
79 virtual ~InputChunk() = default;
80 virtual ArrayRef<uint8_t> data() const = 0;
81
82 // Verifies the existing data at relocation targets matches our expectations.
83 // This is performed only debug builds as an extra sanity check.
84 void verifyRelocTargets() const;
85
86 ArrayRef<WasmRelocation> Relocations;
87 Kind SectionKind;
88};
89
90// Represents a WebAssembly data segment which can be included as part of
91// an output data segments. Note that in WebAssembly, unlike ELF and other
92// formats, used the term "data segment" to refer to the continous regions of
93// memory that make on the data section. See:
94// https://webassembly.github.io/spec/syntax/modules.html#syntax-data
95//
96// For example, by default, clang will produce a separate data section for
97// each global variable.
98class InputSegment : public InputChunk {
99public:
100 InputSegment(const WasmSegment &Seg, ObjFile *F)
101 : InputChunk(F, InputChunk::DataSegment), Segment(Seg) {}
102
103 static bool classof(const InputChunk *C) { return C->kind() == DataSegment; }
104
105 uint32_t getAlignment() const { return Segment.Data.Alignment; }
106 StringRef getName() const override { return Segment.Data.Name; }
107 StringRef getDebugName() const override { return StringRef(); }
108 uint32_t getComdat() const override { return Segment.Data.Comdat; }
109 uint32_t getInputSectionOffset() const override {
110 return Segment.SectionOffset;
111 }
112
113 const OutputSegment *OutputSeg = nullptr;
114 int32_t OutputSegmentOffset = 0;
115
116protected:
117 ArrayRef<uint8_t> data() const override { return Segment.Data.Content; }
118
119 const WasmSegment &Segment;
120};
121
122// Represents a single wasm function within and input file. These are
123// combined to create the final output CODE section.
124class InputFunction : public InputChunk {
125public:
126 InputFunction(const WasmSignature &S, const WasmFunction *Func, ObjFile *F)
127 : InputChunk(F, InputChunk::Function), Signature(S), Function(Func) {}
128
129 static bool classof(const InputChunk *C) {
130 return C->kind() == InputChunk::Function ||
131 C->kind() == InputChunk::SyntheticFunction;
132 }
133
134 void writeTo(uint8_t *SectionStart) const override;
135 StringRef getName() const override { return Function->SymbolName; }
136 StringRef getDebugName() const override { return Function->DebugName; }
137 uint32_t getComdat() const override { return Function->Comdat; }
138 uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); }
139 uint32_t getFunctionCodeOffset() const { return Function->CodeOffset; }
140 uint32_t getSize() const override {
141 if (Config->CompressRelocations && File) {
142 assert(CompressedSize)((CompressedSize) ? static_cast<void> (0) : __assert_fail
("CompressedSize", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.h"
, 142, __PRETTY_FUNCTION__))
;
143 return CompressedSize;
144 }
145 return data().size();
146 }
147 uint32_t getInputSize() const override { return Function->Size; }
148 uint32_t getFunctionIndex() const { return FunctionIndex.getValue(); }
149 bool hasFunctionIndex() const { return FunctionIndex.hasValue(); }
150 void setFunctionIndex(uint32_t Index);
151 uint32_t getInputSectionOffset() const override {
152 return Function->CodeSectionOffset;
153 }
154 uint32_t getTableIndex() const { return TableIndex.getValue(); }
155 bool hasTableIndex() const { return TableIndex.hasValue(); }
156 void setTableIndex(uint32_t Index);
157
158 // The size of a given input function can depend on the values of the
159 // LEB relocations within it. This finalizeContents method is called after
160 // all the symbol values have be calcualted but before getSize() is ever
161 // called.
162 void calculateSize();
163
164 const WasmSignature &Signature;
165
166protected:
167 ArrayRef<uint8_t> data() const override {
168 assert(!Config->CompressRelocations)((!Config->CompressRelocations) ? static_cast<void> (
0) : __assert_fail ("!Config->CompressRelocations", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.h"
, 168, __PRETTY_FUNCTION__))
;
169 return File->CodeSection->Content.slice(getInputSectionOffset(),
4
Access to field 'CodeSection' results in a dereference of a null pointer (loaded from field 'File')
170 Function->Size);
171 }
172
173 const WasmFunction *Function;
174 llvm::Optional<uint32_t> FunctionIndex;
175 llvm::Optional<uint32_t> TableIndex;
176 uint32_t CompressedFuncSize = 0;
177 uint32_t CompressedSize = 0;
178};
179
180class SyntheticFunction : public InputFunction {
181public:
182 SyntheticFunction(const WasmSignature &S, StringRef Name,
183 StringRef DebugName = {})
184 : InputFunction(S, nullptr, nullptr), Name(Name), DebugName(DebugName) {
185 SectionKind = InputChunk::SyntheticFunction;
186 }
187
188 static bool classof(const InputChunk *C) {
189 return C->kind() == InputChunk::SyntheticFunction;
190 }
191
192 StringRef getName() const override { return Name; }
193 StringRef getDebugName() const override { return DebugName; }
194 uint32_t getComdat() const override { return UINT32_MAX(4294967295U); }
195
196 void setBody(ArrayRef<uint8_t> Body_) { Body = Body_; }
197
198protected:
199 ArrayRef<uint8_t> data() const override { return Body; }
200
201 StringRef Name;
202 StringRef DebugName;
203 ArrayRef<uint8_t> Body;
204};
205
206// Represents a single Wasm Section within an input file.
207class InputSection : public InputChunk {
208public:
209 InputSection(const WasmSection &S, ObjFile *F)
210 : InputChunk(F, InputChunk::Section), Section(S) {
211 assert(Section.Type == llvm::wasm::WASM_SEC_CUSTOM)((Section.Type == llvm::wasm::WASM_SEC_CUSTOM) ? static_cast<
void> (0) : __assert_fail ("Section.Type == llvm::wasm::WASM_SEC_CUSTOM"
, "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.h"
, 211, __PRETTY_FUNCTION__))
;
212 }
213
214 StringRef getName() const override { return Section.Name; }
215 StringRef getDebugName() const override { return StringRef(); }
216 uint32_t getComdat() const override { return UINT32_MAX(4294967295U); }
217
218protected:
219 ArrayRef<uint8_t> data() const override { return Section.Content; }
220
221 // Offset within the input section. This is only zero since this chunk
222 // type represents an entire input section, not part of one.
223 uint32_t getInputSectionOffset() const override { return 0; }
224
225 const WasmSection &Section;
226};
227
228} // namespace wasm
229
230std::string toString(const wasm::InputChunk *);
231} // namespace lld
232
233#endif // LLD_WASM_INPUT_CHUNKS_H