1//===- ElideSwiftForceLoad.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#include "StripSwiftForceLoad.h"
10
11#include "Config.h"
12#include "InputSection.h"
13#include "OutputSegment.h"
14#include "Symbols.h"
15#include "Target.h"
16
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/Support/TimeProfiler.h"
20
21using namespace llvm;
22using namespace lld;
23using namespace lld::macho;
24
25static constexpr StringRef forceLoadPrefix = "__swift_FORCE_LOAD_$_";
26
27// Returns true if every byte of `isec` is a pointer slot covered by an UNSIGNED
28// pointer relocation to an imported `__swift_FORCE_LOAD_$_*` symbol, i.e.
29// the section exists only to force-load Swift overlays and holds no other data.
30static bool isSwiftForceLoadSection(const ConcatInputSection *isec) {
31 if (isec->relocs.empty())
32 return false;
33
34 if (isec->getSize() != target->wordSize * isec->relocs.size())
35 return false;
36
37 for (const Relocation &r : isec->relocs) {
38 auto *sym = dyn_cast_if_present<Symbol *>(Val: r.referent);
39 auto *dylibSym = dyn_cast_or_null<DylibSymbol>(Val: sym);
40 if (!dylibSym || dylibSym->isDynamicLookup() ||
41 !dylibSym->getName().starts_with(Prefix: forceLoadPrefix))
42 return false;
43 }
44 return true;
45}
46
47void macho::stripSwiftForceLoadFixups() {
48 if (!config->stripSwiftForceLoad)
49 return;
50
51 TimeTraceScope timeScope("Strip Swift FORCE_LOAD fixups");
52
53 for (ConcatInputSection *isec : inputSections) {
54 if (isec->shouldOmitFromOutput() || isec->replacement)
55 continue;
56
57 if (isec->getSegName() != segment_names::data ||
58 isec->getName() != section_names::const_)
59 continue;
60
61 // Never drop a section that exports a symbol clients may link against.
62 if (llvm::any_of(Range&: isec->symbols, P: [](const Defined *d) {
63 return d->isExternal() && !d->privateExtern;
64 }))
65 continue;
66
67 if (!isSwiftForceLoadSection(isec))
68 continue;
69
70 isec->live = false;
71 for (Defined *d : isec->symbols)
72 d->used = false;
73 }
74}
75