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 // sections from output. Unused sections are sections that are not reachable
11ece8a530Spatrick // from known GC-root symbols or sections. Naturally the feature is
12ece8a530Spatrick // implemented as a mark-sweep garbage collector.
13ece8a530Spatrick //
14ece8a530Spatrick // Here's how it works. Each InputSectionBase has a "Live" bit. The bit is off
15ece8a530Spatrick // by default. Starting with GC-root symbols or sections, markLive function
16ece8a530Spatrick // defined in this file visits all reachable sections to set their Live
17ece8a530Spatrick // bits. Writer will then ignore sections whose Live bits are off, so that
18ece8a530Spatrick // such sections are not included into output.
19ece8a530Spatrick //
20ece8a530Spatrick //===----------------------------------------------------------------------===//
21ece8a530Spatrick
22ece8a530Spatrick #include "MarkLive.h"
23*dfe94b16Srobert #include "InputFiles.h"
24ece8a530Spatrick #include "InputSection.h"
25ece8a530Spatrick #include "LinkerScript.h"
26ece8a530Spatrick #include "SymbolTable.h"
27ece8a530Spatrick #include "Symbols.h"
28ece8a530Spatrick #include "SyntheticSections.h"
29ece8a530Spatrick #include "Target.h"
30*dfe94b16Srobert #include "lld/Common/CommonLinkerContext.h"
31ece8a530Spatrick #include "lld/Common/Strings.h"
32ece8a530Spatrick #include "llvm/ADT/STLExtras.h"
33ece8a530Spatrick #include "llvm/Object/ELF.h"
34bb684c34Spatrick #include "llvm/Support/TimeProfiler.h"
35ece8a530Spatrick #include <vector>
36ece8a530Spatrick
37ece8a530Spatrick using namespace llvm;
38ece8a530Spatrick using namespace llvm::ELF;
39ece8a530Spatrick using namespace llvm::object;
40bb684c34Spatrick using namespace llvm::support::endian;
41bb684c34Spatrick using namespace lld;
42bb684c34Spatrick using namespace lld::elf;
43ece8a530Spatrick
44ece8a530Spatrick namespace {
45ece8a530Spatrick template <class ELFT> class MarkLive {
46ece8a530Spatrick public:
MarkLive(unsigned partition)47ece8a530Spatrick MarkLive(unsigned partition) : partition(partition) {}
48ece8a530Spatrick
49ece8a530Spatrick void run();
50ece8a530Spatrick void moveToMain();
51ece8a530Spatrick
52ece8a530Spatrick private:
53ece8a530Spatrick void enqueue(InputSectionBase *sec, uint64_t offset);
54ece8a530Spatrick void markSymbol(Symbol *sym);
55ece8a530Spatrick void mark();
56ece8a530Spatrick
57ece8a530Spatrick template <class RelTy>
581cf9926bSpatrick void resolveReloc(InputSectionBase &sec, RelTy &rel, bool fromFDE);
59ece8a530Spatrick
60ece8a530Spatrick template <class RelTy>
61ece8a530Spatrick void scanEhFrameSection(EhInputSection &eh, ArrayRef<RelTy> rels);
62ece8a530Spatrick
63ece8a530Spatrick // The index of the partition that we are currently processing.
64ece8a530Spatrick unsigned partition;
65ece8a530Spatrick
66ece8a530Spatrick // A list of sections to visit.
671cf9926bSpatrick SmallVector<InputSection *, 0> queue;
68ece8a530Spatrick
69ece8a530Spatrick // There are normally few input sections whose names are valid C
70*dfe94b16Srobert // identifiers, so we just store a SmallVector instead of a multimap.
71*dfe94b16Srobert DenseMap<StringRef, SmallVector<InputSectionBase *, 0>> cNamedSections;
72ece8a530Spatrick };
73ece8a530Spatrick } // namespace
74ece8a530Spatrick
75ece8a530Spatrick template <class ELFT>
getAddend(InputSectionBase & sec,const typename ELFT::Rel & rel)76ece8a530Spatrick static uint64_t getAddend(InputSectionBase &sec,
77ece8a530Spatrick const typename ELFT::Rel &rel) {
78*dfe94b16Srobert return target->getImplicitAddend(sec.content().begin() + rel.r_offset,
79ece8a530Spatrick rel.getType(config->isMips64EL));
80ece8a530Spatrick }
81ece8a530Spatrick
82ece8a530Spatrick template <class ELFT>
getAddend(InputSectionBase & sec,const typename ELFT::Rela & rel)83ece8a530Spatrick static uint64_t getAddend(InputSectionBase &sec,
84ece8a530Spatrick const typename ELFT::Rela &rel) {
85ece8a530Spatrick return rel.r_addend;
86ece8a530Spatrick }
87ece8a530Spatrick
88ece8a530Spatrick template <class ELFT>
89ece8a530Spatrick template <class RelTy>
resolveReloc(InputSectionBase & sec,RelTy & rel,bool fromFDE)90ece8a530Spatrick void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
911cf9926bSpatrick bool fromFDE) {
92ece8a530Spatrick Symbol &sym = sec.getFile<ELFT>()->getRelocTargetSym(rel);
93ece8a530Spatrick
94ece8a530Spatrick // If a symbol is referenced in a live section, it is used.
95ece8a530Spatrick sym.used = true;
96ece8a530Spatrick
97ece8a530Spatrick if (auto *d = dyn_cast<Defined>(&sym)) {
98ece8a530Spatrick auto *relSec = dyn_cast_or_null<InputSectionBase>(d->section);
99ece8a530Spatrick if (!relSec)
100ece8a530Spatrick return;
101ece8a530Spatrick
102ece8a530Spatrick uint64_t offset = d->value;
103ece8a530Spatrick if (d->isSection())
104ece8a530Spatrick offset += getAddend<ELFT>(sec, rel);
105ece8a530Spatrick
1061cf9926bSpatrick // fromFDE being true means this is referenced by a FDE in a .eh_frame
1071cf9926bSpatrick // piece. The relocation points to the described function or to a LSDA. We
1081cf9926bSpatrick // only need to keep the LSDA live, so ignore anything that points to
1091cf9926bSpatrick // executable sections. If the LSDA is in a section group or has the
1101cf9926bSpatrick // SHF_LINK_ORDER flag, we ignore the relocation as well because (a) if the
1111cf9926bSpatrick // associated text section is live, the LSDA will be retained due to section
1121cf9926bSpatrick // group/SHF_LINK_ORDER rules (b) if the associated text section should be
1131cf9926bSpatrick // discarded, marking the LSDA will unnecessarily retain the text section.
1141cf9926bSpatrick if (!(fromFDE && ((relSec->flags & (SHF_EXECINSTR | SHF_LINK_ORDER)) ||
1151cf9926bSpatrick relSec->nextInSectionGroup)))
116ece8a530Spatrick enqueue(relSec, offset);
117ece8a530Spatrick return;
118ece8a530Spatrick }
119ece8a530Spatrick
120ece8a530Spatrick if (auto *ss = dyn_cast<SharedSymbol>(&sym))
121ece8a530Spatrick if (!ss->isWeak())
122*dfe94b16Srobert cast<SharedFile>(ss->file)->isNeeded = true;
123ece8a530Spatrick
124ece8a530Spatrick for (InputSectionBase *sec : cNamedSections.lookup(sym.getName()))
125ece8a530Spatrick enqueue(sec, 0);
126ece8a530Spatrick }
127ece8a530Spatrick
128ece8a530Spatrick // The .eh_frame section is an unfortunate special case.
129ece8a530Spatrick // The section is divided in CIEs and FDEs and the relocations it can have are
130ece8a530Spatrick // * CIEs can refer to a personality function.
131ece8a530Spatrick // * FDEs can refer to a LSDA
132ece8a530Spatrick // * FDEs refer to the function they contain information about
133ece8a530Spatrick // The last kind of relocation cannot keep the referred section alive, or they
134ece8a530Spatrick // would keep everything alive in a common object file. In fact, each FDE is
135ece8a530Spatrick // alive if the section it refers to is alive.
136ece8a530Spatrick // To keep things simple, in here we just ignore the last relocation kind. The
137ece8a530Spatrick // other two keep the referred section alive.
138ece8a530Spatrick //
139ece8a530Spatrick // A possible improvement would be to fully process .eh_frame in the middle of
140ece8a530Spatrick // the gc pass. With that we would be able to also gc some sections holding
141ece8a530Spatrick // LSDAs and personality functions if we found that they were unused.
142ece8a530Spatrick template <class ELFT>
143ece8a530Spatrick template <class RelTy>
scanEhFrameSection(EhInputSection & eh,ArrayRef<RelTy> rels)144ece8a530Spatrick void MarkLive<ELFT>::scanEhFrameSection(EhInputSection &eh,
145ece8a530Spatrick ArrayRef<RelTy> rels) {
146*dfe94b16Srobert for (const EhSectionPiece &cie : eh.cies)
147*dfe94b16Srobert if (cie.firstRelocation != unsigned(-1))
148*dfe94b16Srobert resolveReloc(eh, rels[cie.firstRelocation], false);
149*dfe94b16Srobert for (const EhSectionPiece &fde : eh.fdes) {
150*dfe94b16Srobert size_t firstRelI = fde.firstRelocation;
151ece8a530Spatrick if (firstRelI == (unsigned)-1)
152ece8a530Spatrick continue;
153*dfe94b16Srobert uint64_t pieceEnd = fde.inputOff + fde.size;
1541cf9926bSpatrick for (size_t j = firstRelI, end2 = rels.size();
1551cf9926bSpatrick j < end2 && rels[j].r_offset < pieceEnd; ++j)
156ece8a530Spatrick resolveReloc(eh, rels[j], true);
157ece8a530Spatrick }
158ece8a530Spatrick }
159ece8a530Spatrick
160ece8a530Spatrick // Some sections are used directly by the loader, so they should never be
161ece8a530Spatrick // garbage-collected. This function returns true if a given section is such
162ece8a530Spatrick // section.
isReserved(InputSectionBase * sec)163ece8a530Spatrick static bool isReserved(InputSectionBase *sec) {
164ece8a530Spatrick switch (sec->type) {
165ece8a530Spatrick case SHT_FINI_ARRAY:
166ece8a530Spatrick case SHT_INIT_ARRAY:
167ece8a530Spatrick case SHT_PREINIT_ARRAY:
168ece8a530Spatrick return true;
169ece8a530Spatrick case SHT_NOTE:
170ece8a530Spatrick // SHT_NOTE sections in a group are subject to garbage collection.
171ece8a530Spatrick return !sec->nextInSectionGroup;
172ece8a530Spatrick default:
173*dfe94b16Srobert // Support SHT_PROGBITS .init_array (https://golang.org/issue/50295) and
174*dfe94b16Srobert // .init_array.N (https://github.com/rust-lang/rust/issues/92181) for a
175*dfe94b16Srobert // while.
176ece8a530Spatrick StringRef s = sec->name;
177*dfe94b16Srobert return s == ".init" || s == ".fini" || s.startswith(".init_array") ||
178*dfe94b16Srobert s == ".jcr" || s.startswith(".ctors") || s.startswith(".dtors");
179ece8a530Spatrick }
180ece8a530Spatrick }
181ece8a530Spatrick
182ece8a530Spatrick template <class ELFT>
enqueue(InputSectionBase * sec,uint64_t offset)183ece8a530Spatrick void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset) {
184ece8a530Spatrick // Usually, a whole section is marked as live or dead, but in mergeable
185ece8a530Spatrick // (splittable) sections, each piece of data has independent liveness bit.
186ece8a530Spatrick // So we explicitly tell it which offset is in use.
187ece8a530Spatrick if (auto *ms = dyn_cast<MergeInputSection>(sec))
188*dfe94b16Srobert ms->getSectionPiece(offset).live = true;
189ece8a530Spatrick
190ece8a530Spatrick // Set Sec->Partition to the meet (i.e. the "minimum") of Partition and
191ece8a530Spatrick // Sec->Partition in the following lattice: 1 < other < 0. If Sec->Partition
192ece8a530Spatrick // doesn't change, we don't need to do anything.
193ece8a530Spatrick if (sec->partition == 1 || sec->partition == partition)
194ece8a530Spatrick return;
195ece8a530Spatrick sec->partition = sec->partition ? 1 : partition;
196ece8a530Spatrick
197ece8a530Spatrick // Add input section to the queue.
198ece8a530Spatrick if (InputSection *s = dyn_cast<InputSection>(sec))
199ece8a530Spatrick queue.push_back(s);
200ece8a530Spatrick }
201ece8a530Spatrick
markSymbol(Symbol * sym)202ece8a530Spatrick template <class ELFT> void MarkLive<ELFT>::markSymbol(Symbol *sym) {
203ece8a530Spatrick if (auto *d = dyn_cast_or_null<Defined>(sym))
204ece8a530Spatrick if (auto *isec = dyn_cast_or_null<InputSectionBase>(d->section))
205ece8a530Spatrick enqueue(isec, d->value);
206ece8a530Spatrick }
207ece8a530Spatrick
208ece8a530Spatrick // This is the main function of the garbage collector.
209ece8a530Spatrick // Starting from GC-root sections, this function visits all reachable
210ece8a530Spatrick // sections to set their "Live" bits.
run()211ece8a530Spatrick template <class ELFT> void MarkLive<ELFT>::run() {
212ece8a530Spatrick // Add GC root symbols.
213ece8a530Spatrick
214ece8a530Spatrick // Preserve externally-visible symbols if the symbols defined by this
215ece8a530Spatrick // file can interrupt other ELF file's symbols at runtime.
216*dfe94b16Srobert for (Symbol *sym : symtab.getSymbols())
217ece8a530Spatrick if (sym->includeInDynsym() && sym->partition == partition)
218ece8a530Spatrick markSymbol(sym);
219ece8a530Spatrick
220ece8a530Spatrick // If this isn't the main partition, that's all that we need to preserve.
221ece8a530Spatrick if (partition != 1) {
222ece8a530Spatrick mark();
223ece8a530Spatrick return;
224ece8a530Spatrick }
225ece8a530Spatrick
226*dfe94b16Srobert markSymbol(symtab.find(config->entry));
227*dfe94b16Srobert markSymbol(symtab.find(config->init));
228*dfe94b16Srobert markSymbol(symtab.find(config->fini));
229ece8a530Spatrick for (StringRef s : config->undefined)
230*dfe94b16Srobert markSymbol(symtab.find(s));
231ece8a530Spatrick for (StringRef s : script->referencedSymbols)
232*dfe94b16Srobert markSymbol(symtab.find(s));
233ece8a530Spatrick
234ece8a530Spatrick // Mark .eh_frame sections as live because there are usually no relocations
235ece8a530Spatrick // that point to .eh_frames. Otherwise, the garbage collector would drop
236ece8a530Spatrick // all of them. We also want to preserve personality routines and LSDA
237ece8a530Spatrick // referenced by .eh_frame sections, so we scan them for that here.
238*dfe94b16Srobert for (EhInputSection *eh : ctx.ehInputSections) {
239*dfe94b16Srobert const RelsOrRelas<ELFT> rels = eh->template relsOrRelas<ELFT>();
240*dfe94b16Srobert if (rels.areRelocsRel())
241*dfe94b16Srobert scanEhFrameSection(*eh, rels.rels);
242*dfe94b16Srobert else if (rels.relas.size())
243*dfe94b16Srobert scanEhFrameSection(*eh, rels.relas);
244ece8a530Spatrick }
245*dfe94b16Srobert for (InputSectionBase *sec : ctx.inputSections) {
2461cf9926bSpatrick if (sec->flags & SHF_GNU_RETAIN) {
2471cf9926bSpatrick enqueue(sec, 0);
2481cf9926bSpatrick continue;
2491cf9926bSpatrick }
250ece8a530Spatrick if (sec->flags & SHF_LINK_ORDER)
251ece8a530Spatrick continue;
252ece8a530Spatrick
253*dfe94b16Srobert // Usually, non-SHF_ALLOC sections are not removed even if they are
254*dfe94b16Srobert // unreachable through relocations because reachability is not a good signal
255*dfe94b16Srobert // whether they are garbage or not (e.g. there is usually no section
256*dfe94b16Srobert // referring to a .comment section, but we want to keep it.) When a
257*dfe94b16Srobert // non-SHF_ALLOC section is retained, we also retain sections dependent on
258*dfe94b16Srobert // it.
259*dfe94b16Srobert //
260*dfe94b16Srobert // Note on SHF_LINK_ORDER: Such sections contain metadata and they
261*dfe94b16Srobert // have a reverse dependency on the InputSection they are linked with.
262*dfe94b16Srobert // We are able to garbage collect them.
263*dfe94b16Srobert //
264*dfe94b16Srobert // Note on SHF_REL{,A}: Such sections reach here only when -r
265*dfe94b16Srobert // or --emit-reloc were given. And they are subject of garbage
266*dfe94b16Srobert // collection because, if we remove a text section, we also
267*dfe94b16Srobert // remove its relocation section.
268*dfe94b16Srobert //
269*dfe94b16Srobert // Note on nextInSectionGroup: The ELF spec says that group sections are
270*dfe94b16Srobert // included or omitted as a unit. We take the interpretation that:
271*dfe94b16Srobert //
272*dfe94b16Srobert // - Group members (nextInSectionGroup != nullptr) are subject to garbage
273*dfe94b16Srobert // collection.
274*dfe94b16Srobert // - Groups members are retained or discarded as a unit.
275*dfe94b16Srobert if (!(sec->flags & SHF_ALLOC)) {
276*dfe94b16Srobert bool isRel = sec->type == SHT_REL || sec->type == SHT_RELA;
277*dfe94b16Srobert if (!isRel && !sec->nextInSectionGroup) {
278*dfe94b16Srobert sec->markLive();
279*dfe94b16Srobert for (InputSection *isec : sec->dependentSections)
280*dfe94b16Srobert isec->markLive();
281*dfe94b16Srobert }
282*dfe94b16Srobert }
283*dfe94b16Srobert
284*dfe94b16Srobert // Preserve special sections and those which are specified in linker
285*dfe94b16Srobert // script KEEP command.
286ece8a530Spatrick if (isReserved(sec) || script->shouldKeep(sec)) {
287ece8a530Spatrick enqueue(sec, 0);
2881cf9926bSpatrick } else if ((!config->zStartStopGC || sec->name.startswith("__libc_")) &&
2891cf9926bSpatrick isValidCIdentifier(sec->name)) {
2901cf9926bSpatrick // As a workaround for glibc libc.a before 2.34
2911cf9926bSpatrick // (https://sourceware.org/PR27492), retain __libc_atexit and similar
2921cf9926bSpatrick // sections regardless of zStartStopGC.
293*dfe94b16Srobert cNamedSections[saver().save("__start_" + sec->name)].push_back(sec);
294*dfe94b16Srobert cNamedSections[saver().save("__stop_" + sec->name)].push_back(sec);
295ece8a530Spatrick }
296ece8a530Spatrick }
297ece8a530Spatrick
298ece8a530Spatrick mark();
299ece8a530Spatrick }
300ece8a530Spatrick
mark()301ece8a530Spatrick template <class ELFT> void MarkLive<ELFT>::mark() {
302ece8a530Spatrick // Mark all reachable sections.
303ece8a530Spatrick while (!queue.empty()) {
304ece8a530Spatrick InputSectionBase &sec = *queue.pop_back_val();
305ece8a530Spatrick
306*dfe94b16Srobert const RelsOrRelas<ELFT> rels = sec.template relsOrRelas<ELFT>();
307*dfe94b16Srobert for (const typename ELFT::Rel &rel : rels.rels)
308ece8a530Spatrick resolveReloc(sec, rel, false);
309*dfe94b16Srobert for (const typename ELFT::Rela &rel : rels.relas)
310ece8a530Spatrick resolveReloc(sec, rel, false);
311ece8a530Spatrick
312ece8a530Spatrick for (InputSectionBase *isec : sec.dependentSections)
313ece8a530Spatrick enqueue(isec, 0);
314ece8a530Spatrick
315ece8a530Spatrick // Mark the next group member.
316ece8a530Spatrick if (sec.nextInSectionGroup)
317ece8a530Spatrick enqueue(sec.nextInSectionGroup, 0);
318ece8a530Spatrick }
319ece8a530Spatrick }
320ece8a530Spatrick
321ece8a530Spatrick // Move the sections for some symbols to the main partition, specifically ifuncs
322ece8a530Spatrick // (because they can result in an IRELATIVE being added to the main partition's
323ece8a530Spatrick // GOT, which means that the ifunc must be available when the main partition is
324ece8a530Spatrick // loaded) and TLS symbols (because we only know how to correctly process TLS
325ece8a530Spatrick // relocations for the main partition).
326ece8a530Spatrick //
327ece8a530Spatrick // We also need to move sections whose names are C identifiers that are referred
328ece8a530Spatrick // to from __start_/__stop_ symbols because there will only be one set of
329ece8a530Spatrick // symbols for the whole program.
moveToMain()330ece8a530Spatrick template <class ELFT> void MarkLive<ELFT>::moveToMain() {
331*dfe94b16Srobert for (ELFFileBase *file : ctx.objectFiles)
332ece8a530Spatrick for (Symbol *s : file->getSymbols())
333ece8a530Spatrick if (auto *d = dyn_cast<Defined>(s))
334ece8a530Spatrick if ((d->type == STT_GNU_IFUNC || d->type == STT_TLS) && d->section &&
335ece8a530Spatrick d->section->isLive())
336ece8a530Spatrick markSymbol(s);
337ece8a530Spatrick
338*dfe94b16Srobert for (InputSectionBase *sec : ctx.inputSections) {
339ece8a530Spatrick if (!sec->isLive() || !isValidCIdentifier(sec->name))
340ece8a530Spatrick continue;
341*dfe94b16Srobert if (symtab.find(("__start_" + sec->name).str()) ||
342*dfe94b16Srobert symtab.find(("__stop_" + sec->name).str()))
343ece8a530Spatrick enqueue(sec, 0);
344ece8a530Spatrick }
345ece8a530Spatrick
346ece8a530Spatrick mark();
347ece8a530Spatrick }
348ece8a530Spatrick
349ece8a530Spatrick // Before calling this function, Live bits are off for all
350ece8a530Spatrick // input sections. This function make some or all of them on
351ece8a530Spatrick // so that they are emitted to the output file.
markLive()352bb684c34Spatrick template <class ELFT> void elf::markLive() {
353bb684c34Spatrick llvm::TimeTraceScope timeScope("markLive");
354*dfe94b16Srobert // If --gc-sections is not given, retain all input sections.
355ece8a530Spatrick if (!config->gcSections) {
356ece8a530Spatrick // If a DSO defines a symbol referenced in a regular object, it is needed.
357*dfe94b16Srobert for (Symbol *sym : symtab.getSymbols())
358ece8a530Spatrick if (auto *s = dyn_cast<SharedSymbol>(sym))
359ece8a530Spatrick if (s->isUsedInRegularObj && !s->isWeak())
360*dfe94b16Srobert cast<SharedFile>(s->file)->isNeeded = true;
361ece8a530Spatrick return;
362ece8a530Spatrick }
363ece8a530Spatrick
364*dfe94b16Srobert for (InputSectionBase *sec : ctx.inputSections)
365*dfe94b16Srobert sec->markDead();
366ece8a530Spatrick
367ece8a530Spatrick // Follow the graph to mark all live sections.
368ece8a530Spatrick for (unsigned curPart = 1; curPart <= partitions.size(); ++curPart)
369ece8a530Spatrick MarkLive<ELFT>(curPart).run();
370ece8a530Spatrick
371ece8a530Spatrick // If we have multiple partitions, some sections need to live in the main
372ece8a530Spatrick // partition even if they were allocated to a loadable partition. Move them
373ece8a530Spatrick // there now.
374ece8a530Spatrick if (partitions.size() != 1)
375ece8a530Spatrick MarkLive<ELFT>(1).moveToMain();
376ece8a530Spatrick
377ece8a530Spatrick // Report garbage-collected sections.
378ece8a530Spatrick if (config->printGcSections)
379*dfe94b16Srobert for (InputSectionBase *sec : ctx.inputSections)
380ece8a530Spatrick if (!sec->isLive())
381ece8a530Spatrick message("removing unused section " + toString(sec));
382ece8a530Spatrick }
383ece8a530Spatrick
384bb684c34Spatrick template void elf::markLive<ELF32LE>();
385bb684c34Spatrick template void elf::markLive<ELF32BE>();
386bb684c34Spatrick template void elf::markLive<ELF64LE>();
387bb684c34Spatrick template void elf::markLive<ELF64BE>();
388