xref: /freebsd/contrib/llvm-project/lld/MachO/MarkLive.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1fe6060f1SDimitry Andric //===- MarkLive.cpp -------------------------------------------------------===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric 
9fe6060f1SDimitry Andric #include "MarkLive.h"
10fe6060f1SDimitry Andric #include "Config.h"
11fe6060f1SDimitry Andric #include "OutputSegment.h"
12fe6060f1SDimitry Andric #include "SymbolTable.h"
13fe6060f1SDimitry Andric #include "Symbols.h"
14fe6060f1SDimitry Andric #include "UnwindInfoSection.h"
15bdd1243dSDimitry Andric 
16bdd1243dSDimitry Andric #include "lld/Common/ErrorHandler.h"
17fe6060f1SDimitry Andric #include "llvm/Support/TimeProfiler.h"
18fe6060f1SDimitry Andric 
19bdd1243dSDimitry Andric #include "mach-o/compact_unwind_encoding.h"
20bdd1243dSDimitry Andric 
21bdd1243dSDimitry Andric namespace lld::macho {
22fe6060f1SDimitry Andric 
23fe6060f1SDimitry Andric using namespace llvm;
24fe6060f1SDimitry Andric using namespace llvm::MachO;
25fe6060f1SDimitry Andric 
2681ad6265SDimitry Andric struct WhyLiveEntry {
2781ad6265SDimitry Andric   InputSection *isec;
2881ad6265SDimitry Andric   // Keep track of the entry that caused us to mark `isec` as live.
2981ad6265SDimitry Andric   const WhyLiveEntry *prev;
30fe6060f1SDimitry Andric 
WhyLiveEntrylld::macho::WhyLiveEntry3181ad6265SDimitry Andric   WhyLiveEntry(InputSection *isec, const WhyLiveEntry *prev)
3281ad6265SDimitry Andric       : isec(isec), prev(prev) {}
3381ad6265SDimitry Andric };
34fe6060f1SDimitry Andric 
3581ad6265SDimitry Andric // Type-erased interface to MarkLiveImpl. Used for adding roots to the liveness
3681ad6265SDimitry Andric // graph.
3781ad6265SDimitry Andric class MarkLive {
3881ad6265SDimitry Andric public:
3981ad6265SDimitry Andric   virtual void enqueue(InputSection *isec, uint64_t off) = 0;
4081ad6265SDimitry Andric   virtual void addSym(Symbol *s) = 0;
4181ad6265SDimitry Andric   virtual void markTransitively() = 0;
4281ad6265SDimitry Andric   virtual ~MarkLive() = default;
4381ad6265SDimitry Andric };
4481ad6265SDimitry Andric 
4581ad6265SDimitry Andric template <bool RecordWhyLive> class MarkLiveImpl : public MarkLive {
4681ad6265SDimitry Andric public:
4781ad6265SDimitry Andric   // -why_live is a rarely used option, so we don't want support for that flag
4881ad6265SDimitry Andric   // to slow down the main -dead_strip code path. As such, we employ templates
4981ad6265SDimitry Andric   // to avoid the usage of WhyLiveEntry in the main code path. This saves us
5081ad6265SDimitry Andric   // from needless allocations and pointer indirections.
5181ad6265SDimitry Andric   using WorklistEntry =
5281ad6265SDimitry Andric       std::conditional_t<RecordWhyLive, WhyLiveEntry, InputSection>;
5381ad6265SDimitry Andric 
enqueue(InputSection * isec,uint64_t off)5481ad6265SDimitry Andric   void enqueue(InputSection *isec, uint64_t off) override {
5581ad6265SDimitry Andric     enqueue(isec, off, nullptr);
5681ad6265SDimitry Andric   }
addSym(Symbol * s)5781ad6265SDimitry Andric   void addSym(Symbol *s) override { addSym(s, nullptr); }
5881ad6265SDimitry Andric   void markTransitively() override;
5981ad6265SDimitry Andric 
6081ad6265SDimitry Andric private:
6181ad6265SDimitry Andric   void enqueue(InputSection *isec, uint64_t off, const WorklistEntry *prev);
6281ad6265SDimitry Andric   void addSym(Symbol *s, const WorklistEntry *prev);
6381ad6265SDimitry Andric   const InputSection *getInputSection(const WorklistEntry *) const;
6481ad6265SDimitry Andric   WorklistEntry *makeEntry(InputSection *, const WorklistEntry *prev) const;
6581ad6265SDimitry Andric 
6681ad6265SDimitry Andric   // We build up a worklist of sections which have been marked as live. We
6781ad6265SDimitry Andric   // only push into the worklist when we discover an unmarked section, and we
6881ad6265SDimitry Andric   // mark as we push, so sections never appear twice in the list. Literal
6981ad6265SDimitry Andric   // sections cannot contain references to other sections, so we only store
7081ad6265SDimitry Andric   // ConcatInputSections in our worklist.
7181ad6265SDimitry Andric   SmallVector<WorklistEntry *, 256> worklist;
7281ad6265SDimitry Andric };
7381ad6265SDimitry Andric 
7481ad6265SDimitry Andric template <bool RecordWhyLive>
enqueue(InputSection * isec,uint64_t off,const typename MarkLiveImpl<RecordWhyLive>::WorklistEntry * prev)7581ad6265SDimitry Andric void MarkLiveImpl<RecordWhyLive>::enqueue(
7681ad6265SDimitry Andric     InputSection *isec, uint64_t off,
7781ad6265SDimitry Andric     const typename MarkLiveImpl<RecordWhyLive>::WorklistEntry *prev) {
78fe6060f1SDimitry Andric   if (isec->isLive(off))
79fe6060f1SDimitry Andric     return;
80fe6060f1SDimitry Andric   isec->markLive(off);
81fe6060f1SDimitry Andric   if (auto s = dyn_cast<ConcatInputSection>(isec)) {
82fe6060f1SDimitry Andric     assert(!s->isCoalescedWeak());
8381ad6265SDimitry Andric     worklist.push_back(makeEntry(s, prev));
84fe6060f1SDimitry Andric   }
8581ad6265SDimitry Andric }
86fe6060f1SDimitry Andric 
printWhyLive(const Symbol * s,const WhyLiveEntry * prev)87bdd1243dSDimitry Andric static void printWhyLive(const Symbol *s, const WhyLiveEntry *prev) {
8881ad6265SDimitry Andric   std::string out = toString(*s) + " from " + toString(s->getFile());
8981ad6265SDimitry Andric   int indent = 2;
9081ad6265SDimitry Andric   for (const WhyLiveEntry *entry = prev; entry;
9181ad6265SDimitry Andric        entry = entry->prev, indent += 2) {
9281ad6265SDimitry Andric     const TinyPtrVector<Defined *> &symbols = entry->isec->symbols;
9381ad6265SDimitry Andric     // With .subsections_with_symbols set, most isecs will have exactly one
9481ad6265SDimitry Andric     // entry in their symbols vector, so we just print the first one.
9581ad6265SDimitry Andric     if (!symbols.empty())
9681ad6265SDimitry Andric       out += "\n" + std::string(indent, ' ') + toString(*symbols.front()) +
9781ad6265SDimitry Andric              " from " + toString(symbols.front()->getFile());
9881ad6265SDimitry Andric   }
9981ad6265SDimitry Andric   message(out);
10081ad6265SDimitry Andric }
10181ad6265SDimitry Andric 
102bdd1243dSDimitry Andric template <bool RecordWhyLive>
addSym(Symbol * s,const typename MarkLiveImpl<RecordWhyLive>::WorklistEntry * prev)103bdd1243dSDimitry Andric void MarkLiveImpl<RecordWhyLive>::addSym(
104bdd1243dSDimitry Andric     Symbol *s,
105bdd1243dSDimitry Andric     const typename MarkLiveImpl<RecordWhyLive>::WorklistEntry *prev) {
106bdd1243dSDimitry Andric   if (s->used)
107bdd1243dSDimitry Andric     return;
108bdd1243dSDimitry Andric   s->used = true;
109bdd1243dSDimitry Andric   if constexpr (RecordWhyLive)
11081ad6265SDimitry Andric     if (!config->whyLive.empty() && config->whyLive.match(s->getName()))
111bdd1243dSDimitry Andric       printWhyLive(s, prev);
112bdd1243dSDimitry Andric   if (auto *d = dyn_cast<Defined>(s)) {
113*0fca6ea1SDimitry Andric     if (d->isec())
114*0fca6ea1SDimitry Andric       enqueue(d->isec(), d->value, prev);
115*0fca6ea1SDimitry Andric     if (d->unwindEntry())
116*0fca6ea1SDimitry Andric       enqueue(d->unwindEntry(), 0, prev);
117bdd1243dSDimitry Andric   }
11881ad6265SDimitry Andric }
11981ad6265SDimitry Andric 
120bdd1243dSDimitry Andric template <bool RecordWhyLive>
getInputSection(const MarkLiveImpl<RecordWhyLive>::WorklistEntry * entry) const121bdd1243dSDimitry Andric const InputSection *MarkLiveImpl<RecordWhyLive>::getInputSection(
122bdd1243dSDimitry Andric     const MarkLiveImpl<RecordWhyLive>::WorklistEntry *entry) const {
123bdd1243dSDimitry Andric   if constexpr (RecordWhyLive)
12481ad6265SDimitry Andric     return entry->isec;
125bdd1243dSDimitry Andric   else
126bdd1243dSDimitry Andric     return entry;
12781ad6265SDimitry Andric }
12881ad6265SDimitry Andric 
129bdd1243dSDimitry Andric template <bool RecordWhyLive>
130bdd1243dSDimitry Andric typename MarkLiveImpl<RecordWhyLive>::WorklistEntry *
makeEntry(InputSection * isec,const MarkLiveImpl<RecordWhyLive>::WorklistEntry * prev) const131bdd1243dSDimitry Andric MarkLiveImpl<RecordWhyLive>::makeEntry(
132bdd1243dSDimitry Andric     InputSection *isec,
133bdd1243dSDimitry Andric     const MarkLiveImpl<RecordWhyLive>::WorklistEntry *prev) const {
134bdd1243dSDimitry Andric   if constexpr (RecordWhyLive) {
13581ad6265SDimitry Andric     if (!isec) {
13681ad6265SDimitry Andric       assert(!prev);
13781ad6265SDimitry Andric       return nullptr;
13881ad6265SDimitry Andric     }
13981ad6265SDimitry Andric     return make<WhyLiveEntry>(isec, prev);
140bdd1243dSDimitry Andric   } else {
14181ad6265SDimitry Andric     return isec;
14281ad6265SDimitry Andric   }
143bdd1243dSDimitry Andric }
14481ad6265SDimitry Andric 
14581ad6265SDimitry Andric template <bool RecordWhyLive>
markTransitively()14681ad6265SDimitry Andric void MarkLiveImpl<RecordWhyLive>::markTransitively() {
14781ad6265SDimitry Andric   do {
14881ad6265SDimitry Andric     // Mark things reachable from GC roots as live.
14981ad6265SDimitry Andric     while (!worklist.empty()) {
15081ad6265SDimitry Andric       WorklistEntry *entry = worklist.pop_back_val();
15181ad6265SDimitry Andric       // Entries that get placed onto the worklist always contain
15281ad6265SDimitry Andric       // ConcatInputSections. `WhyLiveEntry::prev` may point to entries that
15381ad6265SDimitry Andric       // contain other types of InputSections (due to S_ATTR_LIVE_SUPPORT), but
15481ad6265SDimitry Andric       // those entries should never be pushed onto the worklist.
15581ad6265SDimitry Andric       auto *isec = cast<ConcatInputSection>(getInputSection(entry));
15681ad6265SDimitry Andric       assert(isec->live && "We mark as live when pushing onto the worklist!");
15781ad6265SDimitry Andric 
15881ad6265SDimitry Andric       // Mark all symbols listed in the relocation table for this section.
15981ad6265SDimitry Andric       for (const Reloc &r : isec->relocs) {
16081ad6265SDimitry Andric         if (auto *s = r.referent.dyn_cast<Symbol *>())
16181ad6265SDimitry Andric           addSym(s, entry);
16281ad6265SDimitry Andric         else
16381ad6265SDimitry Andric           enqueue(r.referent.get<InputSection *>(), r.addend, entry);
16481ad6265SDimitry Andric       }
16581ad6265SDimitry Andric       for (Defined *d : getInputSection(entry)->symbols)
16681ad6265SDimitry Andric         addSym(d, entry);
16781ad6265SDimitry Andric     }
16881ad6265SDimitry Andric 
16981ad6265SDimitry Andric     // S_ATTR_LIVE_SUPPORT sections are live if they point _to_ a live
17081ad6265SDimitry Andric     // section. Process them in a second pass.
17181ad6265SDimitry Andric     for (ConcatInputSection *isec : inputSections) {
17281ad6265SDimitry Andric       // FIXME: Check if copying all S_ATTR_LIVE_SUPPORT sections into a
17381ad6265SDimitry Andric       // separate vector and only walking that here is faster.
17481ad6265SDimitry Andric       if (!(isec->getFlags() & S_ATTR_LIVE_SUPPORT) || isec->live)
17581ad6265SDimitry Andric         continue;
17681ad6265SDimitry Andric 
17781ad6265SDimitry Andric       for (const Reloc &r : isec->relocs) {
17881ad6265SDimitry Andric         if (auto *s = r.referent.dyn_cast<Symbol *>()) {
17981ad6265SDimitry Andric           if (s->isLive()) {
18081ad6265SDimitry Andric             InputSection *referentIsec = nullptr;
18181ad6265SDimitry Andric             if (auto *d = dyn_cast<Defined>(s))
182*0fca6ea1SDimitry Andric               referentIsec = d->isec();
18381ad6265SDimitry Andric             enqueue(isec, 0, makeEntry(referentIsec, nullptr));
18481ad6265SDimitry Andric           }
18581ad6265SDimitry Andric         } else {
18681ad6265SDimitry Andric           auto *referentIsec = r.referent.get<InputSection *>();
18781ad6265SDimitry Andric           if (referentIsec->isLive(r.addend))
18881ad6265SDimitry Andric             enqueue(isec, 0, makeEntry(referentIsec, nullptr));
18981ad6265SDimitry Andric         }
19081ad6265SDimitry Andric       }
19181ad6265SDimitry Andric     }
19281ad6265SDimitry Andric 
19381ad6265SDimitry Andric     // S_ATTR_LIVE_SUPPORT could have marked additional sections live,
19481ad6265SDimitry Andric     // which in turn could mark additional S_ATTR_LIVE_SUPPORT sections live.
19581ad6265SDimitry Andric     // Iterate. In practice, the second iteration won't mark additional
19681ad6265SDimitry Andric     // S_ATTR_LIVE_SUPPORT sections live.
19781ad6265SDimitry Andric   } while (!worklist.empty());
19881ad6265SDimitry Andric }
19981ad6265SDimitry Andric 
20081ad6265SDimitry Andric // Set live bit on for each reachable chunk. Unmarked (unreachable)
20181ad6265SDimitry Andric // InputSections will be ignored by Writer, so they will be excluded
20281ad6265SDimitry Andric // from the final output.
markLive()20381ad6265SDimitry Andric void markLive() {
20481ad6265SDimitry Andric   TimeTraceScope timeScope("markLive");
20581ad6265SDimitry Andric   MarkLive *marker;
20681ad6265SDimitry Andric   if (config->whyLive.empty())
20781ad6265SDimitry Andric     marker = make<MarkLiveImpl<false>>();
20881ad6265SDimitry Andric   else
20981ad6265SDimitry Andric     marker = make<MarkLiveImpl<true>>();
210fe6060f1SDimitry Andric   // Add GC roots.
211fe6060f1SDimitry Andric   if (config->entry)
21281ad6265SDimitry Andric     marker->addSym(config->entry);
213fe6060f1SDimitry Andric   for (Symbol *sym : symtab->getSymbols()) {
214fe6060f1SDimitry Andric     if (auto *defined = dyn_cast<Defined>(sym)) {
215fe6060f1SDimitry Andric       // -exported_symbol(s_list)
216fe6060f1SDimitry Andric       if (!config->exportedSymbols.empty() &&
217fe6060f1SDimitry Andric           config->exportedSymbols.match(defined->getName())) {
21881ad6265SDimitry Andric         // NOTE: Even though exporting private externs is an ill-defined
21981ad6265SDimitry Andric         // operation, we are purposely not checking for privateExtern in
22081ad6265SDimitry Andric         // order to follow ld64's behavior of treating all exported private
22181ad6265SDimitry Andric         // extern symbols as live, irrespective of whether they are autohide.
22281ad6265SDimitry Andric         marker->addSym(defined);
223fe6060f1SDimitry Andric         continue;
224fe6060f1SDimitry Andric       }
225fe6060f1SDimitry Andric 
226fe6060f1SDimitry Andric       // public symbols explicitly marked .no_dead_strip
227fe6060f1SDimitry Andric       if (defined->referencedDynamically || defined->noDeadStrip) {
22881ad6265SDimitry Andric         marker->addSym(defined);
229fe6060f1SDimitry Andric         continue;
230fe6060f1SDimitry Andric       }
231fe6060f1SDimitry Andric 
23281ad6265SDimitry Andric       // FIXME: When we implement these flags, make symbols from them GC
23381ad6265SDimitry Andric       // roots:
234fe6060f1SDimitry Andric       // * -reexported_symbol(s_list)
235bdd1243dSDimitry Andric       // * -alias_list
236fe6060f1SDimitry Andric       // * -init
237fe6060f1SDimitry Andric 
238fe6060f1SDimitry Andric       // In dylibs and bundles and in executables with -export_dynamic,
239fe6060f1SDimitry Andric       // all external functions are GC roots.
240fe6060f1SDimitry Andric       bool externsAreRoots =
241fe6060f1SDimitry Andric           config->outputType != MH_EXECUTE || config->exportDynamic;
242fe6060f1SDimitry Andric       if (externsAreRoots && !defined->privateExtern) {
24381ad6265SDimitry Andric         marker->addSym(defined);
244fe6060f1SDimitry Andric         continue;
245fe6060f1SDimitry Andric       }
246fe6060f1SDimitry Andric     }
247fe6060f1SDimitry Andric   }
248fe6060f1SDimitry Andric   // -u symbols
249fe6060f1SDimitry Andric   for (Symbol *sym : config->explicitUndefineds)
25081ad6265SDimitry Andric     marker->addSym(sym);
251fe6060f1SDimitry Andric   // local symbols explicitly marked .no_dead_strip
252fe6060f1SDimitry Andric   for (const InputFile *file : inputFiles)
253fe6060f1SDimitry Andric     if (auto *objFile = dyn_cast<ObjFile>(file))
254fe6060f1SDimitry Andric       for (Symbol *sym : objFile->symbols)
255fe6060f1SDimitry Andric         if (auto *defined = dyn_cast_or_null<Defined>(sym))
256fe6060f1SDimitry Andric           if (!defined->isExternal() && defined->noDeadStrip)
25781ad6265SDimitry Andric             marker->addSym(defined);
258fe6060f1SDimitry Andric   if (auto *stubBinder =
259fe6060f1SDimitry Andric           dyn_cast_or_null<DylibSymbol>(symtab->find("dyld_stub_binder")))
26081ad6265SDimitry Andric     marker->addSym(stubBinder);
261fe6060f1SDimitry Andric   for (ConcatInputSection *isec : inputSections) {
262fe6060f1SDimitry Andric     // Sections marked no_dead_strip
263fe6060f1SDimitry Andric     if (isec->getFlags() & S_ATTR_NO_DEAD_STRIP) {
26481ad6265SDimitry Andric       marker->enqueue(isec, 0);
265fe6060f1SDimitry Andric       continue;
266fe6060f1SDimitry Andric     }
267fe6060f1SDimitry Andric 
268fe6060f1SDimitry Andric     // mod_init_funcs, mod_term_funcs sections
269fe6060f1SDimitry Andric     if (sectionType(isec->getFlags()) == S_MOD_INIT_FUNC_POINTERS ||
270fe6060f1SDimitry Andric         sectionType(isec->getFlags()) == S_MOD_TERM_FUNC_POINTERS) {
271bdd1243dSDimitry Andric       assert(!config->emitInitOffsets ||
272bdd1243dSDimitry Andric              sectionType(isec->getFlags()) != S_MOD_INIT_FUNC_POINTERS);
27381ad6265SDimitry Andric       marker->enqueue(isec, 0);
274fe6060f1SDimitry Andric       continue;
275fe6060f1SDimitry Andric     }
276fe6060f1SDimitry Andric   }
277fe6060f1SDimitry Andric 
278bdd1243dSDimitry Andric   for (ConcatInputSection *isec : in.initOffsets->inputs())
279bdd1243dSDimitry Andric     marker->enqueue(isec, 0);
280bdd1243dSDimitry Andric 
28181ad6265SDimitry Andric   marker->markTransitively();
282fe6060f1SDimitry Andric }
283fe6060f1SDimitry Andric 
284bdd1243dSDimitry Andric } // namespace lld::macho
285