diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -68,6 +68,9 @@ unknown, none, safe, +#if defined(__FACEBOOK__) + fbsafe, +#endif all, }; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -772,6 +772,9 @@ auto icfLevel = StringSwitch(icfLevelStr) .Cases("none", "", ICFLevel::none) .Case("safe", ICFLevel::safe) +#if defined(__FACEBOOK__) + .Case("fbsafe", ICFLevel::fbsafe) +#endif .Case("all", ICFLevel::all) .Default(ICFLevel::unknown); if (icfLevel == ICFLevel::unknown) { @@ -1774,6 +1777,10 @@ if (config->icfLevel != ICFLevel::none) { if (config->icfLevel == ICFLevel::safe) markAddrSigSymbols(); +#if defined(__FACEBOOK__) + else if (config->icfLevel == ICFLevel::fbsafe) + markAddrSigSymbolsViaRelocations(); +#endif foldIdenticalSections(/*onlyCfStrings=*/false); } else if (config->dedupLiterals) { foldIdenticalSections(/*onlyCfStrings=*/true); diff --git a/lld/MachO/ICF.h b/lld/MachO/ICF.h --- a/lld/MachO/ICF.h +++ b/lld/MachO/ICF.h @@ -20,6 +20,17 @@ void markSymAsAddrSig(Symbol *s); void foldIdenticalSections(bool onlyCfStrings); +#if defined(__FACEBOOK__) +// This marks symbols as addrsig not by using `__llvm_addrsig` contents, but by +// looking for relocations that suggest a given function's address is being +// taken. This is the approach ld64 takes, and its results are far less +// conservative than what `-faddrsig` emits. Ideally, we'd like to make +// `-faddrsig` less conservative and use that, but this is a good temporary +// solution. +// NOTE: Only implemented for arm64 targets right now. +void markAddrSigSymbolsViaRelocations(); +#endif + } // namespace lld::macho #endif diff --git a/lld/MachO/ICF.cpp b/lld/MachO/ICF.cpp --- a/lld/MachO/ICF.cpp +++ b/lld/MachO/ICF.cpp @@ -394,6 +394,23 @@ } } +#if defined(__FACEBOOK__) +void macho::markAddrSigSymbolsViaRelocations() { + TimeTraceScope timeScope("Mark addrsig symbols via relocations"); + assert(target->cpuType == MachO::CPU_TYPE_ARM64); + for (ConcatInputSection *isec : inputSections) { + for (const Reloc &r : isec->relocs) { + if (r.type != MachO::ARM64_RELOC_PAGEOFF12) + continue; + if (auto *sym = r.referent.dyn_cast()) + if (auto *d = dyn_cast(sym)) + if (d->isec && isCodeSection(d->isec) && !d->weakDefCanBeHidden) + markSymAsAddrSig(sym); + } + } +} +#endif + void macho::foldIdenticalSections(bool onlyCfStrings) { TimeTraceScope timeScope("Fold Identical Code Sections"); // The ICF equivalence-class segregation algorithm relies on pre-computed diff --git a/lld/test/FBMachO/icf-fbsafe.s b/lld/test/FBMachO/icf-fbsafe.s new file mode 100644 --- /dev/null +++ b/lld/test/FBMachO/icf-fbsafe.s @@ -0,0 +1,31 @@ +# REQUIRES: aarch64 +# RUN: rm -rf %t; split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/test.s -o %t/test.o +# RUN: %lld -lSystem -dylib -arch arm64 %t/test.o -o %t/test --icf=fbsafe +# RUN: llvm-objdump --macho --syms %t/test | FileCheck %s + +# CHECK-DAG: [[#%.16x,NOT_ADDRSIG:]] l F __TEXT,__text _not_addrsig +# CHECK-DAG: [[#NOT_ADDRSIG]] l F __TEXT,__text _autohide_addrsig +# CHECK-DAG: [[#NOT_ADDRSIG-4]] l F __TEXT,__text _addrsig + +#--- test.s + +_address_taker: + ldr x1, [x1, _addrsig@PAGEOFF] + ldr x1, [x1, _autohide_addrsig@PAGEOFF] + +_caller: + bl _not_addrsig + +_addrsig: + nop + +.globl _autohide_addrsig +.weak_def_can_be_hidden _autohide_addrsig +_autohide_addrsig: + nop + +_not_addrsig: + nop + +.subsections_via_symbols