xref: /openbsd-src/gnu/llvm/lld/wasm/MarkLive.cpp (revision dfe94b169149f14cc1aee2cf6dad58a8d9a1860c)
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