1 //===- InputChunks.h --------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // An InputChunks represents an indivisible opaque region of a input wasm file.
10 // i.e. a single wasm data segment or a single wasm function.
12 // They are written directly to the mmap'd output file after which relocations
13 // are applied. Because each Chunk is independent they can be written in
16 // Chunks are also unit on which garbage collection (--gc-sections) operates.
18 //===----------------------------------------------------------------------===//
20 #ifndef LLD_WASM_INPUT_CHUNKS_H
21 #define LLD_WASM_INPUT_CHUNKS_H
24 #include "InputFiles.h"
25 #include "lld/Common/ErrorHandler.h"
26 #include "lld/Common/LLVM.h"
27 #include "llvm/Object/Wasm.h"
38 enum Kind
{ DataSegment
, Function
, SyntheticFunction
, Section
};
40 Kind
kind() const { return sectionKind
; }
42 virtual uint32_t getSize() const { return data().size(); }
43 virtual uint32_t getInputSize() const { return getSize(); };
45 virtual void writeTo(uint8_t *sectionStart
) const;
47 ArrayRef
<WasmRelocation
> getRelocations() const { return relocations
; }
48 void setRelocations(ArrayRef
<WasmRelocation
> rs
) { relocations
= rs
; }
50 virtual StringRef
getName() const = 0;
51 virtual StringRef
getDebugName() const = 0;
52 virtual uint32_t getComdat() const = 0;
53 StringRef
getComdatName() const;
54 virtual uint32_t getInputSectionOffset() const = 0;
56 size_t getNumRelocations() const { return relocations
.size(); }
57 void writeRelocations(llvm::raw_ostream
&os
) const;
60 int32_t outputOffset
= 0;
62 // Signals that the section is part of the output. The garbage collector,
63 // and COMDAT handling can set a sections' Live bit.
64 // If GC is disabled, all sections start out as live by default.
67 // Signals the chunk was discarded by COMDAT handling.
68 unsigned discarded
: 1;
71 InputChunk(ObjFile
*f
, Kind k
)
72 : file(f
), live(!config
->gcSections
), discarded(false), sectionKind(k
) {}
73 virtual ~InputChunk() = default;
74 virtual ArrayRef
<uint8_t> data() const = 0;
76 // Verifies the existing data at relocation targets matches our expectations.
77 // This is performed only debug builds as an extra sanity check.
78 void verifyRelocTargets() const;
80 ArrayRef
<WasmRelocation
> relocations
;
84 // Represents a WebAssembly data segment which can be included as part of
85 // an output data segments. Note that in WebAssembly, unlike ELF and other
86 // formats, used the term "data segment" to refer to the continuous regions of
87 // memory that make on the data section. See:
88 // https://webassembly.github.io/spec/syntax/modules.html#syntax-data
90 // For example, by default, clang will produce a separate data section for
91 // each global variable.
92 class InputSegment
: public InputChunk
{
94 InputSegment(const WasmSegment
&seg
, ObjFile
*f
)
95 : InputChunk(f
, InputChunk::DataSegment
), segment(seg
) {}
97 static bool classof(const InputChunk
*c
) { return c
->kind() == DataSegment
; }
99 void generateRelocationCode(raw_ostream
&os
) const;
101 uint32_t getAlignment() const { return segment
.Data
.Alignment
; }
102 StringRef
getName() const override
{ return segment
.Data
.Name
; }
103 StringRef
getDebugName() const override
{ return StringRef(); }
104 uint32_t getComdat() const override
{ return segment
.Data
.Comdat
; }
105 uint32_t getInputSectionOffset() const override
{
106 return segment
.SectionOffset
;
109 const OutputSegment
*outputSeg
= nullptr;
110 int32_t outputSegmentOffset
= 0;
113 ArrayRef
<uint8_t> data() const override
{ return segment
.Data
.Content
; }
115 const WasmSegment
&segment
;
118 // Represents a single wasm function within and input file. These are
119 // combined to create the final output CODE section.
120 class InputFunction
: public InputChunk
{
122 InputFunction(const WasmSignature
&s
, const WasmFunction
*func
, ObjFile
*f
)
123 : InputChunk(f
, InputChunk::Function
), signature(s
), function(func
) {}
125 static bool classof(const InputChunk
*c
) {
126 return c
->kind() == InputChunk::Function
||
127 c
->kind() == InputChunk::SyntheticFunction
;
130 void writeTo(uint8_t *sectionStart
) const override
;
131 StringRef
getName() const override
{ return function
->SymbolName
; }
132 StringRef
getDebugName() const override
{ return function
->DebugName
; }
133 llvm::Optional
<StringRef
> getExportName() const {
134 return function
? function
->ExportName
: llvm::Optional
<StringRef
>();
136 uint32_t getComdat() const override
{ return function
->Comdat
; }
137 uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); }
138 uint32_t getFunctionCodeOffset() const { return function
->CodeOffset
; }
139 uint32_t getSize() const override
{
140 if (config
->compressRelocations
&& file
) {
141 assert(compressedSize
);
142 return compressedSize
;
144 return data().size();
146 uint32_t getInputSize() const override
{ return function
->Size
; }
147 uint32_t getFunctionIndex() const { return functionIndex
.getValue(); }
148 bool hasFunctionIndex() const { return functionIndex
.hasValue(); }
149 void setFunctionIndex(uint32_t index
);
150 uint32_t getInputSectionOffset() const override
{
151 return function
->CodeSectionOffset
;
153 uint32_t getTableIndex() const { return tableIndex
.getValue(); }
154 bool hasTableIndex() const { return tableIndex
.hasValue(); }
155 void setTableIndex(uint32_t index
);
157 // The size of a given input function can depend on the values of the
158 // LEB relocations within it. This finalizeContents method is called after
159 // all the symbol values have be calculated but before getSize() is ever
161 void calculateSize();
163 const WasmSignature
&signature
;
166 ArrayRef
<uint8_t> data() const override
{
167 assert(!config
->compressRelocations
);
168 return file
->codeSection
->Content
.slice(getInputSectionOffset(),
172 const WasmFunction
*function
;
173 llvm::Optional
<uint32_t> functionIndex
;
174 llvm::Optional
<uint32_t> tableIndex
;
175 uint32_t compressedFuncSize
= 0;
176 uint32_t compressedSize
= 0;
179 class SyntheticFunction
: public InputFunction
{
181 SyntheticFunction(const WasmSignature
&s
, StringRef name
,
182 StringRef debugName
= {})
183 : InputFunction(s
, nullptr, nullptr), name(name
), debugName(debugName
) {
184 sectionKind
= InputChunk::SyntheticFunction
;
187 static bool classof(const InputChunk
*c
) {
188 return c
->kind() == InputChunk::SyntheticFunction
;
191 StringRef
getName() const override
{ return name
; }
192 StringRef
getDebugName() const override
{ return debugName
; }
193 uint32_t getComdat() const override
{ return UINT32_MAX
; }
195 void setBody(ArrayRef
<uint8_t> body_
) { body
= body_
; }
198 ArrayRef
<uint8_t> data() const override
{ return body
; }
202 ArrayRef
<uint8_t> body
;
205 // Represents a single Wasm Section within an input file.
206 class InputSection
: public InputChunk
{
208 InputSection(const WasmSection
&s
, ObjFile
*f
)
209 : InputChunk(f
, InputChunk::Section
), section(s
) {
210 assert(section
.Type
== llvm::wasm::WASM_SEC_CUSTOM
);
213 StringRef
getName() const override
{ return section
.Name
; }
214 StringRef
getDebugName() const override
{ return StringRef(); }
215 uint32_t getComdat() const override
{ return UINT32_MAX
; }
217 OutputSection
*outputSec
= nullptr;
220 ArrayRef
<uint8_t> data() const override
{ return section
.Content
; }
222 // Offset within the input section. This is only zero since this chunk
223 // type represents an entire input section, not part of one.
224 uint32_t getInputSectionOffset() const override
{ return 0; }
226 const WasmSection
§ion
;
231 std::string
toString(const wasm::InputChunk
*);
232 StringRef
relocTypeToString(uint8_t relocType
);
236 #endif // LLD_WASM_INPUT_CHUNKS_H