Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport lld fixes from LLVM 15 #13

Merged
merged 85 commits into from
Jan 6, 2023
Merged
Changes from 1 commit
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
c5b7e27
[lld-macho][nfc] Hoist out creation of Section in parseSections()
int3 Feb 2, 2022
ac5e23f
[lld-macho] Fix duplicate symbols with relocatable objects
keith Jan 29, 2022
0e550c4
[lld-macho] Minor clean up: use .find() to check for key existence ra…
oontvoo Feb 3, 2022
428e264
[lld-macho][nfc] Eliminate InputSection::Shared
int3 Feb 4, 2022
1546340
[lld][macho] Add more skip platform check for libSystem re-exports
bc-lee Feb 4, 2022
ede4fe0
[lld-macho] Add -pagezero_size
Link1J Feb 6, 2022
1cc07cc
[lld-macho] Include address offsets in error messages
int3 Feb 8, 2022
c4359b2
Print C-string literals in mapfile
Feb 12, 2022
cbc561b
[lld-macho] Unset ExportDynamic where possible for LTO
int3 Feb 12, 2022
5878c98
[lld-macho][nfc] Factor out callgraph parsing code
int3 Feb 16, 2022
f07d787
[lld-macho] Don't include CommandFlags.h in CommonLinkerContext.h
int3 Feb 17, 2022
2da75dd
[lld-macho] Allow order files and call graph sorting to be used together
speednoisemovement Jan 14, 2022
86c5e65
[lld-macho] Improve hiding of unnamed_addr symbols
int3 Feb 18, 2022
2dc406b
[lld-macho][nfc] Move ICF-specific logic into ICF.cpp
int3 Feb 23, 2022
b40f9cd
[lld-macho][nfc] Refactor MarkLive
int3 Feb 23, 2022
f0ae869
[lld-macho] Implement -why_live (without perf overhead)
int3 Feb 24, 2022
82888fc
[lld/MachO] Fix +asserts build after recent change
rnk Feb 24, 2022
f32c8a0
[lld-macho] Have relocation address included in range-check error mes…
int3 Mar 1, 2022
af3ae34
[lld-macho][nfc] Remove file statics from ICF.cpp
int3 Mar 7, 2022
6ade364
[lld-macho][nfc] Use llvm::function_ref instead of std::function
int3 Mar 5, 2022
dbc294c
[lld-macho][nfc] Track # of ICF calls to `equals*` methods
int3 Mar 7, 2022
65c4433
[lld-macho][nfc] Rename isec -> referentIsec to avoid shadowing
int3 Mar 7, 2022
63d70dd
[lld-macho][nfc] Don't use `stubsHelperIndex` in ICF hash
int3 Mar 7, 2022
e3b6822
[lld-macho][nfc] Reduce size of icfEqClass hash
int3 Mar 7, 2022
9439228
Revert "[lld-macho][nfc] Don't use `stubsHelperIndex` in ICF hash"
nico Mar 7, 2022
0e03fcb
Re-land [lld-macho][nfc] Don't use `stubsHelperIndex` in ICF hash
int3 Mar 7, 2022
88ad6d2
[lld-macho] Deduplicate CFStrings during ICF
int3 Mar 8, 2022
f06266c
[lld-macho] Deduplicate the `__objc_classrefs` section contents
int3 Mar 8, 2022
728ce76
[lld-macho] Align cstrings less conservatively
int3 Mar 10, 2022
8247adf
[lld-macho][nfc] Fix formatting in ld64-vs-lld.rst
int3 Mar 10, 2022
e88e11b
[lld-macho] Don't allocate memory in parallelForEach
int3 Mar 11, 2022
93ec01d
[lld-macho] Avoid using bump-alloc in TrieBuider
oontvoo Mar 14, 2022
fb74624
Revert "[lld-macho] Avoid using bump-alloc in TrieBuider"
Sterling-Augustine Mar 14, 2022
07ac266
Reland "[lld-macho] Avoid using bump-alloc in TrieBuider""
oontvoo Mar 14, 2022
624ddd2
[lld-macho][nfc] Allow Defined symbols to be placed in binding sections
int3 Mar 15, 2022
b9caf0b
[lld-macho] -flat_namespace for dylibs should make all externs interp…
int3 Mar 15, 2022
75678eb
[lld-macho] Set FinalDefinitionInLinkageUnit on most LTO externs
int3 Mar 16, 2022
05a024c
[lld-macho][nfc] Have findContainingSubsection take a Section
int3 Mar 16, 2022
b3ffadc
[lld-macho][nfc] Add comment explaining why a cast<> is safe
int3 Mar 16, 2022
02652db
[lld-macho][nfc] Don't mix file sizes with addresses
int3 Sep 10, 2021
ad91602
[lld][Macho][NFC] Encapsulate priorities map in a priority class
Mar 23, 2022
f69beac
[lld/mac] Give range extension thunks for local symbols local visibility
nico Mar 29, 2022
65608cb
[lld-macho][NFC] Encapsulate symbol priority implementation.
Mar 31, 2022
8077780
Add output filename to UUID hash
speednoisemovement Mar 31, 2022
0a79be8
[lld/mac] Tweak a few comments
nico Apr 1, 2022
fa995de
[lld-macho][nfc] Rearrange order of statements to clarify data depend…
int3 Apr 7, 2022
d8158cf
Fix "result of 32-bit shift implicitly converted to 64 bits" MSVC war…
RKSimon Apr 7, 2022
99187d0
[lld/mac] Don't emit stabs entries for functions folded during ICF
nico Apr 6, 2022
e2014d6
[lld-macho][nfc] Factor out findSymbolAtOffset
int3 Apr 7, 2022
40b45ed
[lld-macho][nfc] Remove indirection when looking up common section me…
int3 Apr 7, 2022
8cd5a5a
[lld/mac] Add some comments and asserts
nico Apr 7, 2022
7276c44
[lld-macho][nfc] Give non-text ConcatOutputSections order-independent…
int3 Apr 7, 2022
70acf4c
Fix format specifier. NFCI.
slackito Apr 7, 2022
59f0d31
[lld-macho] Use fewer indirections in UnwindInfo implementation
int3 Apr 9, 2022
5108940
[lld-macho][nfc] Use includeInSymtab for all symtab-skipping logic
int3 Apr 11, 2022
957f303
[lld-macho][nfc] De-templatize UnwindInfoSection
int3 Apr 13, 2022
b4548d1
[lld/mac] Warn that writing zippered outputs isn't implemented
nico Apr 20, 2022
5131993
[lld-macho] Fix crash on invalid framework tbd
keith Apr 22, 2022
7b72579
[lld-macho][nfc] Simplify unwind section lookup
int3 Apr 22, 2022
cc44dad
[lld-macho] Fix ICF crash when comparing symbol relocs
int3 Apr 22, 2022
ab8c919
[lld-macho] Allow dead_strip to work with exported private extern sym…
thevinster Apr 21, 2022
3174660
[lld-macho] Remove stray debug printf
int3 Apr 23, 2022
3342245
[lld/mac] For catalyst outputs, tolerate implicitly linking against m…
nico Apr 22, 2022
230a86b
[lld/mac] Revert libcompiler_rt.dylib version check change
nico Apr 25, 2022
b3d02d5
[lld] Implement safe icf for MachO
alx32 May 4, 2022
bcdc9ca
[lld/mac] Support writing zippered dylibs and bundles
nico Apr 22, 2022
4b32a85
[lld/macho] Fixes the -ObjC flag
tapthaker May 11, 2022
5cd54ae
[lld-macho] Demangle symbol names in export-symbol error messages whe…
oontvoo May 16, 2022
e921d99
[lld-macho] Stop crash when emitting personalities with -dead_strip
abrachet May 20, 2022
7fef08a
[lld-macho][nfc] Run clang-format on lld/MachO/*.{h,cpp}
oontvoo May 24, 2022
03107c7
[lld-macho] Support -non_global_symbols_strip_list, -non_global_symb…
oontvoo May 20, 2022
3259772
[lld/mac] Cache file IDs of symbols in emitStabs for faster sorting
michaeleisel Jun 1, 2022
b4f990a
[lld/mac] clang-format after f5709066e3b
nico Jun 1, 2022
26d51cf
[lld-macho] Addressed additional post-commit comments from D126046
oontvoo Jun 1, 2022
73b61d3
[lld-macho] Demangle symbol names in duplicate-symbol error when -dem…
oontvoo Jun 3, 2022
55983b9
[lld/mac] Write output sections in parallel
michaeleisel Jun 9, 2022
96a20f7
[lld-macho] Add support for -w
keith Jun 11, 2022
033092e
[lld-macho] Make `--icf=safe` work with LTO
int3 Jun 12, 2022
37e5ac5
[lld-macho][reland] Initial support for EH Frames
int3 Jun 13, 2022
0cb9690
[lld-macho][reland] Support EH frames under arm64
int3 Jun 13, 2022
352dfdb
[ADT] Have ArrayRef::copy() return a MutableArrayRef
int3 Feb 18, 2022
1ce2aec
[lld-macho] Enable EH frame relocation / pruning
int3 Jul 14, 2022
f49c853
[MachO] Fix dead-stripping __eh_frame
smeenai Aug 22, 2022
4d771b2
[lld-macho] Support EH frame pointer encodings that use sdata4
int3 Aug 1, 2022
c082b51
[lld-macho] Fix assertion when two symbols at same addr have unwind info
int3 Jul 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[lld-macho] Implement -why_live (without perf overhead)
This was based off @Thakis' draft in {D103517}. I employed templates to ensure
the support for `-why_live` wouldn't slow down the regular non-why-live code
path.

No stat sig perf difference on my 3.2 GHz 16-Core Intel Xeon W:

             base           diff           difference (95% CI)
  sys_time   1.195 ± 0.015  1.199 ± 0.022  [  -0.4% ..   +1.0%]
  user_time  3.716 ± 0.022  3.701 ± 0.025  [  -0.7% ..   -0.1%]
  wall_time  4.606 ± 0.034  4.597 ± 0.046  [  -0.6% ..   +0.2%]
  samples    44             37

Reviewed By: #lld-macho, thakis

Differential Revision: https://reviews.llvm.org/D120377
  • Loading branch information
int3 authored and gbaraldi committed Jan 6, 2023
commit f0ae8696402b0e0cd78cc0f3b2d6b91d28da876a
1 change: 1 addition & 0 deletions lld/MachO/Config.h
Original file line number Diff line number Diff line change
@@ -182,6 +182,7 @@ struct Configuration {

SymbolPatterns exportedSymbols;
SymbolPatterns unexportedSymbols;
SymbolPatterns whyLive;

bool zeroModTime = false;

5 changes: 5 additions & 0 deletions lld/MachO/Driver.cpp
Original file line number Diff line number Diff line change
@@ -1370,6 +1370,11 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
symtab->addUndefined(cachedName.val(), /*file=*/nullptr,
/*isWeakRef=*/false);

for (const Arg *arg : args.filtered(OPT_why_live))
config->whyLive.insert(arg->getValue());
if (!config->whyLive.empty() && !config->deadStrip)
warn("-why_live has no effect without -dead_strip, ignoring");

config->saveTemps = args.hasArg(OPT_save_temps);

config->adhocCodesign = args.hasFlag(
177 changes: 142 additions & 35 deletions lld/MachO/MarkLive.cpp
Original file line number Diff line number Diff line change
@@ -21,59 +21,157 @@ namespace macho {
using namespace llvm;
using namespace llvm::MachO;

struct WhyLiveEntry {
InputSection *isec;
// Keep track of the entry that caused us to mark `isec` as live.
const WhyLiveEntry *prev;

WhyLiveEntry(InputSection *isec, const WhyLiveEntry *prev)
: isec(isec), prev(prev) {}
};

// Type-erased interface to MarkLiveImpl. Used for adding roots to the liveness
// graph.
class MarkLive {
public:
void enqueue(InputSection *isec, uint64_t off);
void addSym(Symbol *s);
void markTransitively();
virtual void enqueue(InputSection *isec, uint64_t off) = 0;
virtual void addSym(Symbol *s) = 0;
virtual void markTransitively() = 0;
virtual ~MarkLive() = default;
};

template <bool RecordWhyLive> class MarkLiveImpl : public MarkLive {
public:
// -why_live is a rarely used option, so we don't want support for that flag
// to slow down the main -dead_strip code path. As such, we employ templates
// to avoid the usage of WhyLiveEntry in the main code path. This saves us
// from needless allocations and pointer indirections.
using WorklistEntry =
std::conditional_t<RecordWhyLive, WhyLiveEntry, InputSection>;

void enqueue(InputSection *isec, uint64_t off) override {
enqueue(isec, off, nullptr);
}
void addSym(Symbol *s) override { addSym(s, nullptr); }
void markTransitively() override;

private:
void enqueue(InputSection *isec, uint64_t off, const WorklistEntry *prev);
void addSym(Symbol *s, const WorklistEntry *prev);
void printWhyLive(Symbol *s, const WorklistEntry *prev);
const InputSection *getInputSection(const WorklistEntry *) const;
WorklistEntry *makeEntry(InputSection *, const WorklistEntry *prev) const;

// We build up a worklist of sections which have been marked as live. We
// only push into the worklist when we discover an unmarked section, and we
// mark as we push, so sections never appear twice in the list. Literal
// sections cannot contain references to other sections, so we only store
// ConcatInputSections in our worklist.
SmallVector<ConcatInputSection *, 256> worklist;
SmallVector<WorklistEntry *, 256> worklist;
};

void MarkLive::enqueue(InputSection *isec, uint64_t off) {
template <bool RecordWhyLive>
void MarkLiveImpl<RecordWhyLive>::enqueue(
InputSection *isec, uint64_t off,
const typename MarkLiveImpl<RecordWhyLive>::WorklistEntry *prev) {
if (isec->isLive(off))
return;
isec->markLive(off);
if (auto s = dyn_cast<ConcatInputSection>(isec)) {
assert(!s->isCoalescedWeak());
worklist.push_back(s);
worklist.push_back(makeEntry(s, prev));
}
}

void MarkLive::addSym(Symbol *s) {
template <bool RecordWhyLive>
void MarkLiveImpl<RecordWhyLive>::addSym(
Symbol *s,
const typename MarkLiveImpl<RecordWhyLive>::WorklistEntry *prev) {
if (s->used)
return;
s->used = true;
printWhyLive(s, prev);
if (auto *d = dyn_cast<Defined>(s)) {
if (d->isec)
enqueue(d->isec, d->value);
enqueue(d->isec, d->value, prev);
if (d->unwindEntry)
enqueue(d->unwindEntry, 0);
enqueue(d->unwindEntry, 0, prev);
}
}

void MarkLive::markTransitively() {
static void printWhyLiveImpl(const Symbol *s, const WhyLiveEntry *prev) {
std::string out = toString(*s) + " from " + toString(s->getFile());
int indent = 2;
for (const WhyLiveEntry *entry = prev; entry;
entry = entry->prev, indent += 2) {
const TinyPtrVector<Defined *> &symbols = entry->isec->symbols;
// With .subsections_with_symbols set, most isecs will have exactly one
// entry in their symbols vector, so we just print the first one.
if (!symbols.empty())
out += "\n" + std::string(indent, ' ') + toString(*symbols.front()) +
" from " + toString(symbols.front()->getFile());
}
message(out);
}

// NOTE: if/when `constexpr if` becomes available, we can simplify a lot of
// the partial template specializations below.

template <>
void MarkLiveImpl<true>::printWhyLive(Symbol *s, const WhyLiveEntry *prev) {
if (!config->whyLive.empty() && config->whyLive.match(s->getName()))
printWhyLiveImpl(s, prev);
}

template <>
void MarkLiveImpl<false>::printWhyLive(Symbol *s, const InputSection *prev) {}

template <>
const InputSection *
MarkLiveImpl<true>::getInputSection(const WhyLiveEntry *entry) const {
return entry->isec;
}

template <>
const InputSection *
MarkLiveImpl<false>::getInputSection(const InputSection *isec) const {
return isec;
}

template <>
typename MarkLiveImpl<true>::WorklistEntry *MarkLiveImpl<true>::makeEntry(
InputSection *isec, const MarkLiveImpl<true>::WorklistEntry *prev) const {
if (!isec) {
assert(!prev);
return nullptr;
}
return make<WhyLiveEntry>(isec, prev);
}

template <>
typename MarkLiveImpl<false>::WorklistEntry *MarkLiveImpl<false>::makeEntry(
InputSection *isec, const MarkLiveImpl<false>::WorklistEntry *prev) const {
return isec;
}

template <bool RecordWhyLive>
void MarkLiveImpl<RecordWhyLive>::markTransitively() {
do {
// Mark things reachable from GC roots as live.
while (!worklist.empty()) {
ConcatInputSection *s = worklist.pop_back_val();
assert(s->live && "We mark as live when pushing onto the worklist!");
WorklistEntry *entry = worklist.pop_back_val();
assert(getInputSection(entry)->live &&
"We mark as live when pushing onto the worklist!");

// Mark all symbols listed in the relocation table for this section.
for (const Reloc &r : s->relocs) {
for (const Reloc &r : getInputSection(entry)->relocs) {
if (auto *s = r.referent.dyn_cast<Symbol *>())
addSym(s);
addSym(s, entry);
else
enqueue(r.referent.get<InputSection *>(), r.addend);
enqueue(r.referent.get<InputSection *>(), r.addend, entry);
}
for (Defined *d : s->symbols)
addSym(d);
for (Defined *d : getInputSection(entry)->symbols)
addSym(d, entry);
}

// S_ATTR_LIVE_SUPPORT sections are live if they point _to_ a live
@@ -85,13 +183,18 @@ void MarkLive::markTransitively() {
continue;

for (const Reloc &r : isec->relocs) {
bool referentLive;
if (auto *s = r.referent.dyn_cast<Symbol *>())
referentLive = s->isLive();
else
referentLive = r.referent.get<InputSection *>()->isLive(r.addend);
if (referentLive)
enqueue(isec, 0);
if (auto *s = r.referent.dyn_cast<Symbol *>()) {
if (s->isLive()) {
InputSection *referentIsec = nullptr;
if (auto *d = dyn_cast<Defined>(s))
referentIsec = d->isec;
enqueue(isec, 0, makeEntry(referentIsec, nullptr));
}
} else {
auto *referentIsec = r.referent.get<InputSection *>();
if (referentIsec->isLive(r.addend))
enqueue(isec, 0, makeEntry(referentIsec, nullptr));
}
}
}

@@ -107,10 +210,14 @@ void MarkLive::markTransitively() {
// from the final output.
void markLive() {
TimeTraceScope timeScope("markLive");
MarkLive marker;
MarkLive *marker;
if (config->whyLive.empty())
marker = make<MarkLiveImpl<false>>();
else
marker = make<MarkLiveImpl<true>>();
// Add GC roots.
if (config->entry)
marker.addSym(config->entry);
marker->addSym(config->entry);
for (Symbol *sym : symtab->getSymbols()) {
if (auto *defined = dyn_cast<Defined>(sym)) {
// -exported_symbol(s_list)
@@ -121,13 +228,13 @@ void markLive() {
// explicitUndefineds code below would handle this automatically.
assert(!defined->privateExtern &&
"should have been rejected by driver");
marker.addSym(defined);
marker->addSym(defined);
continue;
}

// public symbols explicitly marked .no_dead_strip
if (defined->referencedDynamically || defined->noDeadStrip) {
marker.addSym(defined);
marker->addSym(defined);
continue;
}

@@ -142,40 +249,40 @@ void markLive() {
bool externsAreRoots =
config->outputType != MH_EXECUTE || config->exportDynamic;
if (externsAreRoots && !defined->privateExtern) {
marker.addSym(defined);
marker->addSym(defined);
continue;
}
}
}
// -u symbols
for (Symbol *sym : config->explicitUndefineds)
marker.addSym(sym);
marker->addSym(sym);
// local symbols explicitly marked .no_dead_strip
for (const InputFile *file : inputFiles)
if (auto *objFile = dyn_cast<ObjFile>(file))
for (Symbol *sym : objFile->symbols)
if (auto *defined = dyn_cast_or_null<Defined>(sym))
if (!defined->isExternal() && defined->noDeadStrip)
marker.addSym(defined);
marker->addSym(defined);
if (auto *stubBinder =
dyn_cast_or_null<DylibSymbol>(symtab->find("dyld_stub_binder")))
marker.addSym(stubBinder);
marker->addSym(stubBinder);
for (ConcatInputSection *isec : inputSections) {
// Sections marked no_dead_strip
if (isec->getFlags() & S_ATTR_NO_DEAD_STRIP) {
marker.enqueue(isec, 0);
marker->enqueue(isec, 0);
continue;
}

// mod_init_funcs, mod_term_funcs sections
if (sectionType(isec->getFlags()) == S_MOD_INIT_FUNC_POINTERS ||
sectionType(isec->getFlags()) == S_MOD_TERM_FUNC_POINTERS) {
marker.enqueue(isec, 0);
marker->enqueue(isec, 0);
continue;
}
}

marker.markTransitively();
marker->markTransitively();
}

} // namespace macho
1 change: 0 additions & 1 deletion lld/MachO/Options.td
Original file line number Diff line number Diff line change
@@ -549,7 +549,6 @@ def whyload : Flag<["-"], "whyload">,
def why_live : Separate<["-"], "why_live">,
MetaVarName<"<symbol>">,
HelpText<"Log a chain of references to <symbol>, for use with -dead_strip">,
Flags<[HelpHidden]>,
Group<grp_introspect>;
def print_statistics : Flag<["-"], "print_statistics">,
HelpText<"Log the linker's memory and CPU usage">,
2 changes: 1 addition & 1 deletion lld/MachO/Symbols.h
Original file line number Diff line number Diff line change
@@ -109,7 +109,7 @@ class Symbol {
// True if this symbol was referenced by a regular (non-bitcode) object.
bool isUsedInRegularObj : 1;

// True if an undefined or dylib symbol is used from a live section.
// True if this symbol is used from a live section.
bool used : 1;
};

64 changes: 64 additions & 0 deletions lld/test/MachO/why-live.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# REQUIRES: x86

# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %s -o %t.o
# RUN: %lld -lSystem -dead_strip -why_live _foo -why_live _undef -U _undef \
# RUN: -why_live _support -why_live _support_refs_dylib_fun \
# RUN: -why_live _abs %t.o -o /dev/null 2>&1 | FileCheck %s

## Due to an implementation detail, LLD is not able to report -why_live info for
## absolute symbols. (ld64 has the same shortcoming.)
# CHECK-NOT: _abs
# CHECK: _foo from {{.*}}why-live.s.tmp.o
# CHECK-NEXT: _quux from {{.*}}why-live.s.tmp.o
# CHECK-NEXT: _undef from {{.*}}why-live.s.tmp.o
# CHECK-NEXT: _main from {{.*}}why-live.s.tmp.o
## Our handling of live_support sections can be improved... we should print the
## dylib symbol that keeps _support_refs_dylib_fun alive, instead of printing
## the live_support symbol's name itself. (ld64 seems to have the same issue.)
# CHECK-NEXT: _support_refs_dylib_fun from {{.*}}why-live.s.tmp.o
# CHECK-NEXT: _support_refs_dylib_fun from {{.*}}why-live.s.tmp.o
## Again, this can be improved: we shouldn't be printing _support twice. (ld64
## seems to have the same issue.)
# CHECK-NEXT: _support from {{.*}}why-live.s.tmp.o
# CHECK-NEXT: _support from {{.*}}why-live.s.tmp.o
# CHECK-NEXT: _foo from {{.*}}why-live.s.tmp.o
# CHECK-EMPTY:

.text
_foo:
retq

_bar:
retq

_baz:
callq _foo
retq

.no_dead_strip _quux
_quux:
callq _foo
retq

.globl _main
_main:
callq _foo
callq _baz
callq _undef
callq ___isnan
retq

.globl _abs
_abs = 0x1000

.section __TEXT,support,regular,live_support
_support:
callq _foo
callq _abs
retq

_support_refs_dylib_fun:
callq ___isnan
retq

.subsections_via_symbols