1ece8a530Spatrick //===- MarkLive.cpp -------------------------------------------------------===//
2ece8a530Spatrick //
3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ece8a530Spatrick //
7ece8a530Spatrick //===----------------------------------------------------------------------===//
8ece8a530Spatrick //
9ece8a530Spatrick // This file implements --gc-sections, which is a feature to remove unused
10ece8a530Spatrick // chunks from the output. Unused chunks are those that are not reachable from
11ece8a530Spatrick // known root symbols or chunks. This feature is implemented as a mark-sweep
12ece8a530Spatrick // garbage collector.
13ece8a530Spatrick //
14ece8a530Spatrick // Here's how it works. Each InputChunk has a "Live" bit. The bit is off by
15ece8a530Spatrick // default. Starting with the GC-roots, visit all reachable chunks and set their
16ece8a530Spatrick // Live bits. The Writer will then ignore chunks whose Live bits are off, so
17ece8a530Spatrick // that such chunk are not appear in the output.
18ece8a530Spatrick //
19ece8a530Spatrick //===----------------------------------------------------------------------===//
20ece8a530Spatrick
21ece8a530Spatrick #include "MarkLive.h"
22ece8a530Spatrick #include "Config.h"
23ece8a530Spatrick #include "InputChunks.h"
241cf9926bSpatrick #include "InputElement.h"
25ece8a530Spatrick #include "SymbolTable.h"
26ece8a530Spatrick #include "Symbols.h"
27ece8a530Spatrick
28ece8a530Spatrick #define DEBUG_TYPE "lld"
29ece8a530Spatrick
30ece8a530Spatrick using namespace llvm;
31ece8a530Spatrick using namespace llvm::wasm;
32ece8a530Spatrick
33ece8a530Spatrick namespace lld {
34ece8a530Spatrick namespace wasm {
35ece8a530Spatrick
36ece8a530Spatrick namespace {
37ece8a530Spatrick
38ece8a530Spatrick class MarkLive {
39ece8a530Spatrick public:
40ece8a530Spatrick void run();
41ece8a530Spatrick
42ece8a530Spatrick private:
43ece8a530Spatrick void enqueue(Symbol *sym);
441cf9926bSpatrick void enqueueInitFunctions(const ObjFile *sym);
45ece8a530Spatrick void mark();
461cf9926bSpatrick bool isCallCtorsLive();
47ece8a530Spatrick
48ece8a530Spatrick // A list of chunks to visit.
49ece8a530Spatrick SmallVector<InputChunk *, 256> queue;
50ece8a530Spatrick };
51ece8a530Spatrick
52ece8a530Spatrick } // namespace
53ece8a530Spatrick
enqueue(Symbol * sym)54ece8a530Spatrick void MarkLive::enqueue(Symbol *sym) {
55ece8a530Spatrick if (!sym || sym->isLive())
56ece8a530Spatrick return;
57ece8a530Spatrick LLVM_DEBUG(dbgs() << "markLive: " << sym->getName() << "\n");
581cf9926bSpatrick
591cf9926bSpatrick InputFile *file = sym->getFile();
601cf9926bSpatrick bool needInitFunctions = file && !file->isLive() && sym->isDefined();
611cf9926bSpatrick
62ece8a530Spatrick sym->markLive();
631cf9926bSpatrick
641cf9926bSpatrick // Mark ctor functions in the object that defines this symbol live.
651cf9926bSpatrick // The ctor functions are all referenced by the synthetic callCtors
661cf9926bSpatrick // function. However, this function does not contain relocations so we
671cf9926bSpatrick // have to manually mark the ctors as live.
681cf9926bSpatrick if (needInitFunctions)
691cf9926bSpatrick enqueueInitFunctions(cast<ObjFile>(file));
701cf9926bSpatrick
71ece8a530Spatrick if (InputChunk *chunk = sym->getChunk())
72ece8a530Spatrick queue.push_back(chunk);
731cf9926bSpatrick }
74ece8a530Spatrick
75ece8a530Spatrick // The ctor functions are all referenced by the synthetic callCtors
76ece8a530Spatrick // function. However, this function does not contain relocations so we
771cf9926bSpatrick // have to manually mark the ctors as live.
enqueueInitFunctions(const ObjFile * obj)781cf9926bSpatrick void MarkLive::enqueueInitFunctions(const ObjFile *obj) {
79ece8a530Spatrick const WasmLinkingData &l = obj->getWasmObj()->linkingData();
80ece8a530Spatrick for (const WasmInitFunc &f : l.InitFunctions) {
81ece8a530Spatrick auto *initSym = obj->getFunctionSymbol(f.Symbol);
82ece8a530Spatrick if (!initSym->isDiscarded())
83ece8a530Spatrick enqueue(initSym);
84ece8a530Spatrick }
85ece8a530Spatrick }
86ece8a530Spatrick
run()87ece8a530Spatrick void MarkLive::run() {
88ece8a530Spatrick // Add GC root symbols.
89ece8a530Spatrick if (!config->entry.empty())
90ece8a530Spatrick enqueue(symtab->find(config->entry));
91ece8a530Spatrick
92ece8a530Spatrick // We need to preserve any no-strip or exported symbol
93*dfe94b16Srobert for (Symbol *sym : symtab->symbols())
94ece8a530Spatrick if (sym->isNoStrip() || sym->isExported())
95ece8a530Spatrick enqueue(sym);
96ece8a530Spatrick
971cf9926bSpatrick if (WasmSym::callDtors)
981cf9926bSpatrick enqueue(WasmSym::callDtors);
99ece8a530Spatrick
1001cf9926bSpatrick // Enqueue constructors in objects explicitly live from the command-line.
1011cf9926bSpatrick for (const ObjFile *obj : symtab->objectFiles)
1021cf9926bSpatrick if (obj->isLive())
1031cf9926bSpatrick enqueueInitFunctions(obj);
104ece8a530Spatrick
105ece8a530Spatrick mark();
1061cf9926bSpatrick
1071cf9926bSpatrick // If we have any non-discarded init functions, mark `__wasm_call_ctors` as
1081cf9926bSpatrick // live so that we assign it an index and call it.
1091cf9926bSpatrick if (isCallCtorsLive())
1101cf9926bSpatrick WasmSym::callCtors->markLive();
111ece8a530Spatrick }
112ece8a530Spatrick
mark()113ece8a530Spatrick void MarkLive::mark() {
114ece8a530Spatrick // Follow relocations to mark all reachable chunks.
115ece8a530Spatrick while (!queue.empty()) {
116ece8a530Spatrick InputChunk *c = queue.pop_back_val();
117ece8a530Spatrick
118ece8a530Spatrick for (const WasmRelocation reloc : c->getRelocations()) {
119ece8a530Spatrick if (reloc.Type == R_WASM_TYPE_INDEX_LEB)
120ece8a530Spatrick continue;
121ece8a530Spatrick Symbol *sym = c->file->getSymbol(reloc.Index);
122ece8a530Spatrick
123ece8a530Spatrick // If the function has been assigned the special index zero in the table,
124ece8a530Spatrick // the relocation doesn't pull in the function body, since the function
125ece8a530Spatrick // won't actually go in the table (the runtime will trap attempts to call
126ece8a530Spatrick // that index, since we don't use it). A function with a table index of
127ece8a530Spatrick // zero is only reachable via "call", not via "call_indirect". The stub
128ece8a530Spatrick // functions used for weak-undefined symbols have this behaviour (compare
129ece8a530Spatrick // equal to null pointer, only reachable via direct call).
130ece8a530Spatrick if (reloc.Type == R_WASM_TABLE_INDEX_SLEB ||
1311cf9926bSpatrick reloc.Type == R_WASM_TABLE_INDEX_SLEB64 ||
1321cf9926bSpatrick reloc.Type == R_WASM_TABLE_INDEX_I32 ||
1331cf9926bSpatrick reloc.Type == R_WASM_TABLE_INDEX_I64) {
134ece8a530Spatrick auto *funcSym = cast<FunctionSymbol>(sym);
1351cf9926bSpatrick if (funcSym->isStub)
136ece8a530Spatrick continue;
137ece8a530Spatrick }
138ece8a530Spatrick
139ece8a530Spatrick enqueue(sym);
140ece8a530Spatrick }
141ece8a530Spatrick }
142ece8a530Spatrick }
143ece8a530Spatrick
markLive()144ece8a530Spatrick void markLive() {
145ece8a530Spatrick if (!config->gcSections)
146ece8a530Spatrick return;
147ece8a530Spatrick
148ece8a530Spatrick LLVM_DEBUG(dbgs() << "markLive\n");
149ece8a530Spatrick
150ece8a530Spatrick MarkLive marker;
151ece8a530Spatrick marker.run();
152ece8a530Spatrick
153ece8a530Spatrick // Report garbage-collected sections.
154ece8a530Spatrick if (config->printGcSections) {
155ece8a530Spatrick for (const ObjFile *obj : symtab->objectFiles) {
156ece8a530Spatrick for (InputChunk *c : obj->functions)
157ece8a530Spatrick if (!c->live)
158ece8a530Spatrick message("removing unused section " + toString(c));
159ece8a530Spatrick for (InputChunk *c : obj->segments)
160ece8a530Spatrick if (!c->live)
161ece8a530Spatrick message("removing unused section " + toString(c));
162ece8a530Spatrick for (InputGlobal *g : obj->globals)
163ece8a530Spatrick if (!g->live)
164ece8a530Spatrick message("removing unused section " + toString(g));
1651cf9926bSpatrick for (InputTag *t : obj->tags)
1661cf9926bSpatrick if (!t->live)
1671cf9926bSpatrick message("removing unused section " + toString(t));
1681cf9926bSpatrick for (InputTable *t : obj->tables)
1691cf9926bSpatrick if (!t->live)
1701cf9926bSpatrick message("removing unused section " + toString(t));
171ece8a530Spatrick }
172ece8a530Spatrick for (InputChunk *c : symtab->syntheticFunctions)
173ece8a530Spatrick if (!c->live)
174ece8a530Spatrick message("removing unused section " + toString(c));
175ece8a530Spatrick for (InputGlobal *g : symtab->syntheticGlobals)
176ece8a530Spatrick if (!g->live)
177ece8a530Spatrick message("removing unused section " + toString(g));
1781cf9926bSpatrick for (InputTable *t : symtab->syntheticTables)
1791cf9926bSpatrick if (!t->live)
1801cf9926bSpatrick message("removing unused section " + toString(t));
181ece8a530Spatrick }
182ece8a530Spatrick }
183ece8a530Spatrick
isCallCtorsLive()1841cf9926bSpatrick bool MarkLive::isCallCtorsLive() {
1851cf9926bSpatrick // In a reloctable link, we don't call `__wasm_call_ctors`.
1861cf9926bSpatrick if (config->relocatable)
1871cf9926bSpatrick return false;
1881cf9926bSpatrick
1891cf9926bSpatrick // In Emscripten-style PIC, we call `__wasm_call_ctors` which calls
1901cf9926bSpatrick // `__wasm_apply_data_relocs`.
1911cf9926bSpatrick if (config->isPic)
1921cf9926bSpatrick return true;
1931cf9926bSpatrick
1941cf9926bSpatrick // If there are any init functions, mark `__wasm_call_ctors` live so that
1951cf9926bSpatrick // it can call them.
1961cf9926bSpatrick for (const ObjFile *file : symtab->objectFiles) {
1971cf9926bSpatrick const WasmLinkingData &l = file->getWasmObj()->linkingData();
1981cf9926bSpatrick for (const WasmInitFunc &f : l.InitFunctions) {
1991cf9926bSpatrick auto *sym = file->getFunctionSymbol(f.Symbol);
2001cf9926bSpatrick if (!sym->isDiscarded() && sym->isLive())
2011cf9926bSpatrick return true;
2021cf9926bSpatrick }
2031cf9926bSpatrick }
2041cf9926bSpatrick
2051cf9926bSpatrick return false;
2061cf9926bSpatrick }
2071cf9926bSpatrick
208ece8a530Spatrick } // namespace wasm
209ece8a530Spatrick } // namespace lld
210