diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -685,9 +685,6 @@ warn(Twine("unknown --icf=OPTION `") + icfLevelStr + "', defaulting to `none'"); icfLevel = ICFLevel::none; - } else if (icfLevel == ICFLevel::safe) { - warn(Twine("`--icf=safe' is not yet implemented, reverting to `none'")); - icfLevel = ICFLevel::none; } return icfLevel; } @@ -1509,8 +1506,12 @@ // ICF assumes that all literals have been folded already, so we must run // foldIdenticalLiterals before foldIdenticalSections. foldIdenticalLiterals(); - if (config->icfLevel != ICFLevel::none) + if (config->icfLevel != ICFLevel::none) { + if (config->icfLevel == ICFLevel::safe) { + markAddrSigSymbols(inputFiles, &*symtab, &*config); + } foldIdenticalSections(); + } // Write to an output file. if (target->wordSize == 8) diff --git a/lld/MachO/ICF.h b/lld/MachO/ICF.h --- a/lld/MachO/ICF.h +++ b/lld/MachO/ICF.h @@ -9,12 +9,20 @@ #ifndef LLD_MACHO_ICF_H #define LLD_MACHO_ICF_H +#include "InputFiles.h" #include "lld/Common/LLVM.h" +#include "llvm/ADT/SetVector.h" #include namespace lld { namespace macho { +struct Configuration; +class SymbolTable; +class Symbol; +void markAddrSigSymbols(llvm::SetVector &inputFiles, + SymbolTable *symtab, Configuration *config); +void markSymAsAddrSig(Symbol *s); void foldIdenticalSections(); } // namespace macho diff --git a/lld/MachO/ICF.cpp b/lld/MachO/ICF.cpp --- a/lld/MachO/ICF.cpp +++ b/lld/MachO/ICF.cpp @@ -8,11 +8,14 @@ #include "ICF.h" #include "ConcatOutputSection.h" +#include "Config.h" #include "InputSection.h" +#include "SymbolTable.h" #include "Symbols.h" #include "UnwindInfoSection.h" #include "lld/Common/CommonLinkerContext.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/xxhash.h" @@ -354,6 +357,51 @@ } } +void macho::markSymAsAddrSig(Symbol *s) { + if (auto *d = dyn_cast_or_null(s)) { + if (d->isec) { + d->isec->keepUnique = true; + } + } +} + +void macho::markAddrSigSymbols(SetVector &inputFiles, + SymbolTable *symtab, Configuration *config) { + // Symbols in the dynsym could be address-significant in other executables + // or DSOs, so we conservatively mark them as address-significant. + for (Symbol *sym : symtab->getSymbols()) { + Defined *def = dyn_cast_or_null(sym); + if (def && def->referencedDynamically) { + markSymAsAddrSig(sym); + } + } + + for (InputFile *file : inputFiles) { + auto *obj = dyn_cast_or_null(file); + if (!obj) + continue; + + auto *addrSigSection = obj->addrSigSection; + if (!addrSigSection) + continue; + assert(addrSigSection->subsections.size() == 1); + + auto *subSection = &addrSigSection->subsections[0]; + auto &contents = subSection->isec->data; + + const uint8_t *pData = contents.begin(); + while (pData != contents.end()) { + unsigned size; + const char *err; + uint32_t symIndex = decodeULEB128(pData, &size, contents.end(), &err); + if (err) + fatal(toString(file) + ": could not decode addrsig section: " + err); + markSymAsAddrSig(obj->symbols[symIndex]); + pData += size; + } + } +} + void macho::foldIdenticalSections() { TimeTraceScope timeScope("Fold Identical Code Sections"); // The ICF equivalence-class segregation algorithm relies on pre-computed @@ -376,6 +424,7 @@ // FIXME: consider non-code __text sections as hashable? bool isHashable = (isCodeSection(isec) || isCfStringSection(isec) || isClassRefsSection(isec)) && + (isec->keepUnique == false) && !isec->shouldOmitFromOutput() && sectionType(isec->getFlags()) == MachO::S_REGULAR; if (isHashable) { diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h --- a/lld/MachO/InputFiles.h +++ b/lld/MachO/InputFiles.h @@ -149,6 +149,7 @@ const uint32_t modTime; std::vector debugSections; std::vector callGraph; + Section *addrSigSection = nullptr; private: Section *compactUnwindSection = nullptr; diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -355,6 +355,9 @@ // spurious duplicate symbol errors, we do not parse these sections. // TODO: Evaluate whether the bitcode metadata is needed. } else { + if (name == section_names::addrSig) + addrSigSection = sections.back(); + auto *isec = make(section, data, align); if (isDebugSection(isec->getFlags()) && isec->getSegName() == segment_names::dwarf) { diff --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h --- a/lld/MachO/InputSection.h +++ b/lld/MachO/InputSection.h @@ -71,6 +71,7 @@ public: // is address assigned? bool isFinal = false; + bool keepUnique = false; uint32_t align = 1; OutputSection *parent = nullptr; @@ -328,6 +329,7 @@ constexpr const char unwindInfo[] = "__unwind_info"; constexpr const char weakBinding[] = "__weak_binding"; constexpr const char zeroFill[] = "__zerofill"; +constexpr const char addrSig[] = "__llvm_addrsig"; } // namespace section_names