1 | //===- MarkLive.cpp -------------------------------------------------------===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements --gc-sections, which is a feature to remove unused |
10 | // sections from output. Unused sections are sections that are not reachable |
11 | // from known GC-root symbols or sections. Naturally the feature is |
12 | // implemented as a mark-sweep garbage collector. |
13 | // |
14 | // Here's how it works. Each InputSectionBase has a "Live" bit. The bit is off |
15 | // by default. Starting with GC-root symbols or sections, markLive function |
16 | // defined in this file visits all reachable sections to set their Live |
17 | // bits. Writer will then ignore sections whose Live bits are off, so that |
18 | // such sections are not included into output. |
19 | // |
20 | //===----------------------------------------------------------------------===// |
21 | |
22 | #include "MarkLive.h" |
23 | #include "InputFiles.h" |
24 | #include "InputSection.h" |
25 | #include "LinkerScript.h" |
26 | #include "SymbolTable.h" |
27 | #include "Symbols.h" |
28 | #include "SyntheticSections.h" |
29 | #include "Target.h" |
30 | #include "lld/Common/Strings.h" |
31 | #include "llvm/ADT/DenseMapInfoVariant.h" |
32 | #include "llvm/ADT/STLExtras.h" |
33 | #include "llvm/Support/TimeProfiler.h" |
34 | #include <variant> |
35 | #include <vector> |
36 | |
37 | using namespace llvm; |
38 | using namespace llvm::ELF; |
39 | using namespace llvm::object; |
40 | using namespace llvm::support::endian; |
41 | using namespace lld; |
42 | using namespace lld::elf; |
43 | |
44 | namespace { |
45 | using SecOffset = std::pair<InputSectionBase *, unsigned>; |
46 | |
47 | // Something that can have an independent reason for being live. |
48 | using LiveItem = std::variant<InputSectionBase *, Symbol *, SecOffset>; |
49 | |
50 | // The most proximate reason that something is live. |
51 | struct LiveReason { |
52 | std::optional<LiveItem> item; |
53 | StringRef desc; |
54 | }; |
55 | |
56 | template <class ELFT, bool TrackWhyLive> class MarkLive { |
57 | public: |
58 | MarkLive(Ctx &ctx, unsigned partition) : ctx(ctx), partition(partition) {} |
59 | |
60 | void run(); |
61 | void moveToMain(); |
62 | void printWhyLive(Symbol *s) const; |
63 | |
64 | private: |
65 | void enqueue(InputSectionBase *sec, uint64_t offset, Symbol *sym, |
66 | LiveReason reason); |
67 | void markSymbol(Symbol *sym, StringRef reason); |
68 | void mark(); |
69 | |
70 | template <class RelTy> |
71 | void resolveReloc(InputSectionBase &sec, RelTy &rel, bool fromFDE); |
72 | |
73 | template <class RelTy> |
74 | void scanEhFrameSection(EhInputSection &eh, ArrayRef<RelTy> rels); |
75 | |
76 | Ctx &ctx; |
77 | // The index of the partition that we are currently processing. |
78 | unsigned partition; |
79 | |
80 | // A list of sections to visit. |
81 | SmallVector<InputSection *, 0> queue; |
82 | |
83 | // There are normally few input sections whose names are valid C |
84 | // identifiers, so we just store a SmallVector instead of a multimap. |
85 | DenseMap<StringRef, SmallVector<InputSectionBase *, 0>> cNamedSections; |
86 | |
87 | // The most proximate reason that something is live. This forms a DAG between |
88 | // LiveItems. Acyclicality is maintained by only admitting the first |
89 | // discovered reason for each LiveItem; this captures the acyclic region of |
90 | // the liveness graph around the GC roots. |
91 | DenseMap<LiveItem, LiveReason> whyLive; |
92 | }; |
93 | } // namespace |
94 | |
95 | template <class ELFT> |
96 | static uint64_t getAddend(Ctx &ctx, InputSectionBase &sec, |
97 | const typename ELFT::Rel &rel) { |
98 | return ctx.target->getImplicitAddend(buf: sec.content().begin() + rel.r_offset, |
99 | type: rel.getType(ctx.arg.isMips64EL)); |
100 | } |
101 | |
102 | template <class ELFT> |
103 | static uint64_t getAddend(Ctx &, InputSectionBase &sec, |
104 | const typename ELFT::Rela &rel) { |
105 | return rel.r_addend; |
106 | } |
107 | |
108 | // Currently, we assume all input CREL relocations have an explicit addend. |
109 | template <class ELFT> |
110 | static uint64_t getAddend(Ctx &, InputSectionBase &sec, |
111 | const typename ELFT::Crel &rel) { |
112 | return rel.r_addend; |
113 | } |
114 | |
115 | template <class ELFT, bool TrackWhyLive> |
116 | template <class RelTy> |
117 | void MarkLive<ELFT, TrackWhyLive>::resolveReloc(InputSectionBase &sec, |
118 | RelTy &rel, bool fromFDE) { |
119 | // If a symbol is referenced in a live section, it is used. |
120 | Symbol &sym = sec.file->getRelocTargetSym(rel); |
121 | sym.used = true; |
122 | |
123 | LiveReason reason; |
124 | if (TrackWhyLive) |
125 | reason = {.item: SecOffset(&sec, rel.r_offset), .desc: "referenced by" }; |
126 | |
127 | if (auto *d = dyn_cast<Defined>(Val: &sym)) { |
128 | auto *relSec = dyn_cast_or_null<InputSectionBase>(Val: d->section); |
129 | if (!relSec) |
130 | return; |
131 | |
132 | uint64_t offset = d->value; |
133 | if (d->isSection()) |
134 | offset += getAddend<ELFT>(ctx, sec, rel); |
135 | |
136 | // fromFDE being true means this is referenced by a FDE in a .eh_frame |
137 | // piece. The relocation points to the described function or to a LSDA. We |
138 | // only need to keep the LSDA live, so ignore anything that points to |
139 | // executable sections. If the LSDA is in a section group or has the |
140 | // SHF_LINK_ORDER flag, we ignore the relocation as well because (a) if the |
141 | // associated text section is live, the LSDA will be retained due to section |
142 | // group/SHF_LINK_ORDER rules (b) if the associated text section should be |
143 | // discarded, marking the LSDA will unnecessarily retain the text section. |
144 | if (!(fromFDE && ((relSec->flags & (SHF_EXECINSTR | SHF_LINK_ORDER)) || |
145 | relSec->nextInSectionGroup))) { |
146 | Symbol *canonicalSym = d; |
147 | if (TrackWhyLive && d->isSection()) { |
148 | // This is expensive, so ideally this would be deferred until it's known |
149 | // whether this reference contributes to a printed whyLive chain, but |
150 | // that determination cannot be made without knowing the enclosing |
151 | // symbol. |
152 | if (Symbol *s = relSec->getEnclosingSymbol(offset)) |
153 | canonicalSym = s; |
154 | else |
155 | canonicalSym = nullptr; |
156 | } |
157 | enqueue(sec: relSec, offset, sym: canonicalSym, reason); |
158 | } |
159 | return; |
160 | } |
161 | |
162 | if (auto *ss = dyn_cast<SharedSymbol>(Val: &sym)) { |
163 | if (!ss->isWeak()) { |
164 | cast<SharedFile>(Val: ss->file)->isNeeded = true; |
165 | if (TrackWhyLive) |
166 | whyLive.try_emplace(Key: &sym, Args&: reason); |
167 | } |
168 | } |
169 | |
170 | for (InputSectionBase *sec : cNamedSections.lookup(Val: sym.getName())) |
171 | enqueue(sec, /*offset=*/0, /*sym=*/nullptr, reason); |
172 | } |
173 | |
174 | // The .eh_frame section is an unfortunate special case. |
175 | // The section is divided in CIEs and FDEs and the relocations it can have are |
176 | // * CIEs can refer to a personality function. |
177 | // * FDEs can refer to a LSDA |
178 | // * FDEs refer to the function they contain information about |
179 | // The last kind of relocation cannot keep the referred section alive, or they |
180 | // would keep everything alive in a common object file. In fact, each FDE is |
181 | // alive if the section it refers to is alive. |
182 | // To keep things simple, in here we just ignore the last relocation kind. The |
183 | // other two keep the referred section alive. |
184 | // |
185 | // A possible improvement would be to fully process .eh_frame in the middle of |
186 | // the gc pass. With that we would be able to also gc some sections holding |
187 | // LSDAs and personality functions if we found that they were unused. |
188 | template <class ELFT, bool TrackWhyLive> |
189 | template <class RelTy> |
190 | void MarkLive<ELFT, TrackWhyLive>::scanEhFrameSection(EhInputSection &eh, |
191 | ArrayRef<RelTy> rels) { |
192 | for (const EhSectionPiece &cie : eh.cies) |
193 | if (cie.firstRelocation != unsigned(-1)) |
194 | resolveReloc(eh, rels[cie.firstRelocation], false); |
195 | for (const EhSectionPiece &fde : eh.fdes) { |
196 | size_t firstRelI = fde.firstRelocation; |
197 | if (firstRelI == (unsigned)-1) |
198 | continue; |
199 | uint64_t pieceEnd = fde.inputOff + fde.size; |
200 | for (size_t j = firstRelI, end2 = rels.size(); |
201 | j < end2 && rels[j].r_offset < pieceEnd; ++j) |
202 | resolveReloc(eh, rels[j], true); |
203 | } |
204 | } |
205 | |
206 | // Some sections are used directly by the loader, so they should never be |
207 | // garbage-collected. This function returns true if a given section is such |
208 | // section. |
209 | static bool isReserved(InputSectionBase *sec) { |
210 | switch (sec->type) { |
211 | case SHT_FINI_ARRAY: |
212 | case SHT_INIT_ARRAY: |
213 | case SHT_PREINIT_ARRAY: |
214 | return true; |
215 | case SHT_NOTE: |
216 | // SHT_NOTE sections in a group are subject to garbage collection. |
217 | return !sec->nextInSectionGroup; |
218 | default: |
219 | // Support SHT_PROGBITS .init_array (https://golang.org/issue/50295) and |
220 | // .init_array.N (https://github.com/rust-lang/rust/issues/92181) for a |
221 | // while. |
222 | StringRef s = sec->name; |
223 | return s == ".init" || s == ".fini" || s.starts_with(Prefix: ".init_array" ) || |
224 | s == ".jcr" || s.starts_with(Prefix: ".ctors" ) || s.starts_with(Prefix: ".dtors" ); |
225 | } |
226 | } |
227 | |
228 | template <class ELFT, bool TrackWhyLive> |
229 | void MarkLive<ELFT, TrackWhyLive>::enqueue(InputSectionBase *sec, |
230 | uint64_t offset, Symbol *sym, |
231 | LiveReason reason) { |
232 | // Usually, a whole section is marked as live or dead, but in mergeable |
233 | // (splittable) sections, each piece of data has independent liveness bit. |
234 | // So we explicitly tell it which offset is in use. |
235 | if (auto *ms = dyn_cast<MergeInputSection>(Val: sec)) |
236 | ms->getSectionPiece(offset).live = true; |
237 | |
238 | // Set Sec->Partition to the meet (i.e. the "minimum") of Partition and |
239 | // Sec->Partition in the following lattice: 1 < other < 0. If Sec->Partition |
240 | // doesn't change, we don't need to do anything. |
241 | if (sec->partition == 1 || sec->partition == partition) |
242 | return; |
243 | sec->partition = sec->partition ? 1 : partition; |
244 | |
245 | if (TrackWhyLive) { |
246 | if (sym) { |
247 | // If a specific symbol is referenced, that keeps it live. The symbol then |
248 | // keeps its section live. |
249 | whyLive.try_emplace(Key: sym, Args&: reason); |
250 | whyLive.try_emplace(Key: sec, Args: LiveReason{.item: sym, .desc: "contained live symbol" }); |
251 | } else { |
252 | // Otherwise, the reference generically keeps the section live. |
253 | whyLive.try_emplace(Key: sec, Args&: reason); |
254 | } |
255 | } |
256 | |
257 | // Add input section to the queue. |
258 | if (InputSection *s = dyn_cast<InputSection>(Val: sec)) |
259 | queue.push_back(Elt: s); |
260 | } |
261 | |
262 | // Print the stack of reasons that the given symbol is live. |
263 | template <class ELFT, bool TrackWhyLive> |
264 | void MarkLive<ELFT, TrackWhyLive>::printWhyLive(Symbol *s) const { |
265 | // Skip dead symbols. A symbol is dead if it belongs to a dead section. |
266 | if (auto *d = dyn_cast<Defined>(Val: s)) { |
267 | auto *sec = dyn_cast_or_null<InputSectionBase>(Val: d->section); |
268 | if (sec && !sec->isLive()) |
269 | return; |
270 | } |
271 | |
272 | auto msg = Msg(ctx); |
273 | |
274 | const auto printSymbol = [&](Symbol *s) { |
275 | msg << s->file << ":(" << s << ')'; |
276 | }; |
277 | |
278 | msg << "live symbol: " ; |
279 | printSymbol(s); |
280 | |
281 | LiveItem cur = s; |
282 | while (true) { |
283 | auto it = whyLive.find(Val: cur); |
284 | LiveReason reason; |
285 | // If there is a specific reason this item is live... |
286 | if (it != whyLive.end()) { |
287 | reason = it->second; |
288 | } else { |
289 | // This item is live, but it has no tracked reason. It must be an |
290 | // unreferenced symbol in a live section or a symbol with no section. |
291 | InputSectionBase *sec = nullptr; |
292 | if (auto *d = dyn_cast<Defined>(Val: std::get<Symbol *>(v&: cur))) |
293 | sec = dyn_cast_or_null<InputSectionBase>(Val: d->section); |
294 | reason = sec ? LiveReason{.item: sec, .desc: "in live section" } |
295 | : LiveReason{.item: std::nullopt, .desc: "no section" }; |
296 | } |
297 | |
298 | if (!reason.item) { |
299 | msg << " (" << reason.desc << ')'; |
300 | break; |
301 | } |
302 | |
303 | msg << "\n>>> " << reason.desc << ": " ; |
304 | // The reason may not yet have been resolved to a symbol; do so now. |
305 | if (std::holds_alternative<SecOffset>(v: *reason.item)) { |
306 | const auto &so = std::get<SecOffset>(v&: *reason.item); |
307 | InputSectionBase *sec = so.first; |
308 | Defined *sym = sec->getEnclosingSymbol(offset: so.second); |
309 | cur = sym ? LiveItem(sym) : LiveItem(sec); |
310 | } else { |
311 | cur = *reason.item; |
312 | } |
313 | |
314 | if (std::holds_alternative<Symbol *>(v: cur)) |
315 | printSymbol(std::get<Symbol *>(v&: cur)); |
316 | else |
317 | msg << std::get<InputSectionBase *>(v&: cur); |
318 | } |
319 | } |
320 | |
321 | template <class ELFT, bool TrackWhyLive> |
322 | void MarkLive<ELFT, TrackWhyLive>::markSymbol(Symbol *sym, StringRef reason) { |
323 | if (auto *d = dyn_cast_or_null<Defined>(Val: sym)) |
324 | if (auto *isec = dyn_cast_or_null<InputSectionBase>(Val: d->section)) |
325 | enqueue(sec: isec, offset: d->value, sym, reason: {std::nullopt, reason}); |
326 | } |
327 | |
328 | // This is the main function of the garbage collector. |
329 | // Starting from GC-root sections, this function visits all reachable |
330 | // sections to set their "Live" bits. |
331 | template <class ELFT, bool TrackWhyLive> |
332 | void MarkLive<ELFT, TrackWhyLive>::run() { |
333 | // Add GC root symbols. |
334 | |
335 | // Preserve externally-visible symbols if the symbols defined by this |
336 | // file can interpose other ELF file's symbols at runtime. |
337 | for (Symbol *sym : ctx.symtab->getSymbols()) |
338 | if (sym->isExported && sym->partition == partition) |
339 | markSymbol(sym, reason: "externally visible symbol; may interpose" ); |
340 | |
341 | // If this isn't the main partition, that's all that we need to preserve. |
342 | if (partition != 1) { |
343 | mark(); |
344 | return; |
345 | } |
346 | |
347 | markSymbol(sym: ctx.symtab->find(name: ctx.arg.entry), reason: "entry point" ); |
348 | markSymbol(sym: ctx.symtab->find(name: ctx.arg.init), reason: "initializer function" ); |
349 | markSymbol(sym: ctx.symtab->find(name: ctx.arg.fini), reason: "finalizer function" ); |
350 | for (StringRef s : ctx.arg.undefined) |
351 | markSymbol(sym: ctx.symtab->find(name: s), reason: "undefined command line flag" ); |
352 | for (StringRef s : ctx.script->referencedSymbols) |
353 | markSymbol(sym: ctx.symtab->find(name: s), reason: "referenced by linker script" ); |
354 | for (auto [symName, _] : ctx.symtab->cmseSymMap) { |
355 | markSymbol(sym: ctx.symtab->cmseSymMap[symName].sym, reason: "ARM CMSE symbol" ); |
356 | markSymbol(sym: ctx.symtab->cmseSymMap[symName].acleSeSym, reason: "ARM CMSE symbol" ); |
357 | } |
358 | |
359 | // Mark .eh_frame sections as live because there are usually no relocations |
360 | // that point to .eh_frames. Otherwise, the garbage collector would drop |
361 | // all of them. We also want to preserve personality routines and LSDA |
362 | // referenced by .eh_frame sections, so we scan them for that here. |
363 | for (EhInputSection *eh : ctx.ehInputSections) { |
364 | const RelsOrRelas<ELFT> rels = |
365 | eh->template relsOrRelas<ELFT>(/*supportsCrel=*/false); |
366 | if (rels.areRelocsRel()) |
367 | scanEhFrameSection(*eh, rels.rels); |
368 | else if (rels.relas.size()) |
369 | scanEhFrameSection(*eh, rels.relas); |
370 | } |
371 | for (InputSectionBase *sec : ctx.inputSections) { |
372 | if (sec->flags & SHF_GNU_RETAIN) { |
373 | enqueue(sec, /*offset=*/0, /*sym=*/nullptr, reason: {std::nullopt, "retained" }); |
374 | continue; |
375 | } |
376 | if (sec->flags & SHF_LINK_ORDER) |
377 | continue; |
378 | |
379 | // Usually, non-SHF_ALLOC sections are not removed even if they are |
380 | // unreachable through relocations because reachability is not a good signal |
381 | // whether they are garbage or not (e.g. there is usually no section |
382 | // referring to a .comment section, but we want to keep it.) When a |
383 | // non-SHF_ALLOC section is retained, we also retain sections dependent on |
384 | // it. |
385 | // |
386 | // Note on SHF_LINK_ORDER: Such sections contain metadata and they |
387 | // have a reverse dependency on the InputSection they are linked with. |
388 | // We are able to garbage collect them. |
389 | // |
390 | // Note on SHF_REL{,A}: Such sections reach here only when -r |
391 | // or --emit-reloc were given. And they are subject of garbage |
392 | // collection because, if we remove a text section, we also |
393 | // remove its relocation section. |
394 | // |
395 | // Note on nextInSectionGroup: The ELF spec says that group sections are |
396 | // included or omitted as a unit. We take the interpretation that: |
397 | // |
398 | // - Group members (nextInSectionGroup != nullptr) are subject to garbage |
399 | // collection. |
400 | // - Groups members are retained or discarded as a unit. |
401 | if (!(sec->flags & SHF_ALLOC)) { |
402 | if (!isStaticRelSecType(type: sec->type) && !sec->nextInSectionGroup) { |
403 | sec->markLive(); |
404 | for (InputSection *isec : sec->dependentSections) |
405 | isec->markLive(); |
406 | } |
407 | } |
408 | |
409 | // Preserve special sections and those which are specified in linker |
410 | // script KEEP command. |
411 | if (isReserved(sec)) { |
412 | enqueue(sec, /*offset=*/0, /*sym=*/nullptr, reason: {std::nullopt, "reserved" }); |
413 | } else if (ctx.script->shouldKeep(s: sec)) { |
414 | enqueue(sec, /*offset=*/0, /*sym=*/nullptr, |
415 | reason: {std::nullopt, "KEEP in linker script" }); |
416 | } else if ((!ctx.arg.zStartStopGC || sec->name.starts_with(Prefix: "__libc_" )) && |
417 | isValidCIdentifier(s: sec->name)) { |
418 | // As a workaround for glibc libc.a before 2.34 |
419 | // (https://sourceware.org/PR27492), retain __libc_atexit and similar |
420 | // sections regardless of zStartStopGC. |
421 | cNamedSections[ctx.saver.save(S: "__start_" + sec->name)].push_back(Elt: sec); |
422 | cNamedSections[ctx.saver.save(S: "__stop_" + sec->name)].push_back(Elt: sec); |
423 | } |
424 | } |
425 | |
426 | mark(); |
427 | |
428 | if (TrackWhyLive) { |
429 | const auto handleSym = [&](Symbol *sym) { |
430 | if (llvm::any_of(ctx.arg.whyLive, [sym](const llvm::GlobPattern &pat) { |
431 | return pat.match(S: sym->getName()); |
432 | })) |
433 | printWhyLive(s: sym); |
434 | }; |
435 | |
436 | for (Symbol *sym : ctx.symtab->getSymbols()) |
437 | handleSym(sym); |
438 | for (ELFFileBase *file : ctx.objectFiles) |
439 | for (Symbol *sym : file->getSymbols()) |
440 | if (sym->isLocal()) |
441 | handleSym(sym); |
442 | } |
443 | } |
444 | |
445 | template <class ELFT, bool TrackWhyLive> |
446 | void MarkLive<ELFT, TrackWhyLive>::mark() { |
447 | // Mark all reachable sections. |
448 | while (!queue.empty()) { |
449 | InputSectionBase &sec = *queue.pop_back_val(); |
450 | |
451 | const RelsOrRelas<ELFT> rels = sec.template relsOrRelas<ELFT>(); |
452 | for (const typename ELFT::Rel &rel : rels.rels) |
453 | resolveReloc(sec, rel, false); |
454 | for (const typename ELFT::Rela &rel : rels.relas) |
455 | resolveReloc(sec, rel, false); |
456 | for (const typename ELFT::Crel &rel : rels.crels) |
457 | resolveReloc(sec, rel, false); |
458 | |
459 | for (InputSectionBase *isec : sec.dependentSections) |
460 | enqueue(sec: isec, /*offset=*/0, /*sym=*/nullptr, |
461 | reason: {&sec, "depended on by section" }); |
462 | |
463 | // Mark the next group member. |
464 | if (sec.nextInSectionGroup) |
465 | enqueue(sec: sec.nextInSectionGroup, /*offset=*/0, /*sym=*/nullptr, |
466 | reason: {&sec, "in section group with" }); |
467 | } |
468 | } |
469 | |
470 | // Move the sections for some symbols to the main partition, specifically ifuncs |
471 | // (because they can result in an IRELATIVE being added to the main partition's |
472 | // GOT, which means that the ifunc must be available when the main partition is |
473 | // loaded) and TLS symbols (because we only know how to correctly process TLS |
474 | // relocations for the main partition). |
475 | // |
476 | // We also need to move sections whose names are C identifiers that are referred |
477 | // to from __start_/__stop_ symbols because there will only be one set of |
478 | // symbols for the whole program. |
479 | template <class ELFT, bool TrackWhyLive> |
480 | void MarkLive<ELFT, TrackWhyLive>::moveToMain() { |
481 | for (ELFFileBase *file : ctx.objectFiles) |
482 | for (Symbol *s : file->getSymbols()) |
483 | if (auto *d = dyn_cast<Defined>(Val: s)) |
484 | if ((d->type == STT_GNU_IFUNC || d->type == STT_TLS) && d->section && |
485 | d->section->isLive()) |
486 | markSymbol(sym: s, /*reason=*/{}); |
487 | |
488 | for (InputSectionBase *sec : ctx.inputSections) { |
489 | if (!sec->isLive() || !isValidCIdentifier(s: sec->name)) |
490 | continue; |
491 | if (ctx.symtab->find(name: ("__start_" + sec->name).str()) || |
492 | ctx.symtab->find(name: ("__stop_" + sec->name).str())) |
493 | enqueue(sec, /*offset=*/0, /*sym=*/nullptr, /*reason=*/{}); |
494 | } |
495 | |
496 | mark(); |
497 | } |
498 | |
499 | // Before calling this function, Live bits are off for all |
500 | // input sections. This function make some or all of them on |
501 | // so that they are emitted to the output file. |
502 | template <class ELFT> void elf::markLive(Ctx &ctx) { |
503 | llvm::TimeTraceScope timeScope("markLive" ); |
504 | // If --gc-sections is not given, retain all input sections. |
505 | if (!ctx.arg.gcSections) { |
506 | // If a DSO defines a symbol referenced in a regular object, it is needed. |
507 | for (Symbol *sym : ctx.symtab->getSymbols()) |
508 | if (auto *s = dyn_cast<SharedSymbol>(Val: sym)) |
509 | if (s->isUsedInRegularObj && !s->isWeak()) |
510 | cast<SharedFile>(Val: s->file)->isNeeded = true; |
511 | return; |
512 | } |
513 | |
514 | for (InputSectionBase *sec : ctx.inputSections) |
515 | sec->markDead(); |
516 | |
517 | // Follow the graph to mark all live sections. |
518 | for (unsigned i = 1, e = ctx.partitions.size(); i <= e; ++i) |
519 | if (ctx.arg.whyLive.empty()) |
520 | MarkLive<ELFT, false>(ctx, i).run(); |
521 | else |
522 | MarkLive<ELFT, true>(ctx, i).run(); |
523 | |
524 | // If we have multiple partitions, some sections need to live in the main |
525 | // partition even if they were allocated to a loadable partition. Move them |
526 | // there now. |
527 | if (ctx.partitions.size() != 1) |
528 | MarkLive<ELFT, false>(ctx, 1).moveToMain(); |
529 | |
530 | // Report garbage-collected sections. |
531 | if (ctx.arg.printGcSections) |
532 | for (InputSectionBase *sec : ctx.inputSections) |
533 | if (!sec->isLive()) |
534 | Msg(ctx) << "removing unused section " << sec; |
535 | } |
536 | |
537 | template void elf::markLive<ELF32LE>(Ctx &); |
538 | template void elf::markLive<ELF32BE>(Ctx &); |
539 | template void elf::markLive<ELF64LE>(Ctx &); |
540 | template void elf::markLive<ELF64BE>(Ctx &); |
541 | |