diff options
Diffstat (limited to 'lld/MachO/InputFiles.cpp')
| -rw-r--r-- | lld/MachO/InputFiles.cpp | 430 |
1 files changed, 303 insertions, 127 deletions
diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp index a4fb9035193c..558de4131cb9 100644 --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -70,6 +70,8 @@ #include "llvm/TextAPI/Architecture.h" #include "llvm/TextAPI/InterfaceFile.h" +#include <type_traits> + using namespace llvm; using namespace llvm::MachO; using namespace llvm::support::endian; @@ -173,8 +175,19 @@ static bool checkCompatibility(const InputFile *input) { return true; } +// This cache mostly exists to store system libraries (and .tbds) as they're +// loaded, rather than the input archives, which are already cached at a higher +// level, and other files like the filelist that are only read once. +// Theoretically this caching could be more efficient by hoisting it, but that +// would require altering many callers to track the state. +DenseMap<CachedHashStringRef, MemoryBufferRef> macho::cachedReads; // Open a given file path and return it as a memory-mapped file. Optional<MemoryBufferRef> macho::readFile(StringRef path) { + CachedHashStringRef key(path); + auto entry = cachedReads.find(key); + if (entry != cachedReads.end()) + return entry->second; + ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = MemoryBuffer::getFile(path); if (std::error_code ec = mbOrErr.getError()) { error("cannot open " + path + ": " + ec.message()); @@ -192,7 +205,7 @@ Optional<MemoryBufferRef> macho::readFile(StringRef path) { read32be(&hdr->magic) != FAT_MAGIC) { if (tar) tar->append(relativeToRoot(path), mbref.getBuffer()); - return mbref; + return cachedReads[key] = mbref; } // Object files and archive files may be fat files, which contain multiple @@ -217,7 +230,8 @@ Optional<MemoryBufferRef> macho::readFile(StringRef path) { error(path + ": slice extends beyond end of file"); if (tar) tar->append(relativeToRoot(path), mbref.getBuffer()); - return MemoryBufferRef(StringRef(buf + offset, size), path.copy(bAlloc)); + return cachedReads[key] = MemoryBufferRef(StringRef(buf + offset, size), + path.copy(bAlloc)); } error("unable to find matching architecture in " + path); @@ -227,12 +241,32 @@ Optional<MemoryBufferRef> macho::readFile(StringRef path) { InputFile::InputFile(Kind kind, const InterfaceFile &interface) : id(idCount++), fileKind(kind), name(saver.save(interface.getPath())) {} -template <class Section> -void ObjFile::parseSections(ArrayRef<Section> sections) { - subsections.reserve(sections.size()); +// Some sections comprise of fixed-size records, so instead of splitting them at +// symbol boundaries, we split them based on size. Records are distinct from +// literals in that they may contain references to other sections, instead of +// being leaf nodes in the InputSection graph. +// +// Note that "record" is a term I came up with. In contrast, "literal" is a term +// used by the Mach-O format. +static Optional<size_t> getRecordSize(StringRef segname, StringRef name) { + if (name == section_names::cfString) { + if (config->icfLevel != ICFLevel::none && segname == segment_names::data) + return target->wordSize == 8 ? 32 : 16; + } else if (name == section_names::compactUnwind) { + if (segname == segment_names::ld) + return target->wordSize == 8 ? 32 : 20; + } + return {}; +} + +// Parse the sequence of sections within a single LC_SEGMENT(_64). +// Split each section into subsections. +template <class SectionHeader> +void ObjFile::parseSections(ArrayRef<SectionHeader> sectionHeaders) { + sections.reserve(sectionHeaders.size()); auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart()); - for (const Section &sec : sections) { + for (const SectionHeader &sec : sectionHeaders) { StringRef name = StringRef(sec.sectname, strnlen(sec.sectname, sizeof(sec.sectname))); StringRef segname = @@ -243,12 +277,29 @@ void ObjFile::parseSections(ArrayRef<Section> sections) { if (sec.align >= 32) { error("alignment " + std::to_string(sec.align) + " of section " + name + " is too large"); - subsections.push_back({}); + sections.push_back(sec.addr); continue; } uint32_t align = 1 << sec.align; uint32_t flags = sec.flags; + auto splitRecords = [&](int recordSize) -> void { + sections.push_back(sec.addr); + if (data.empty()) + return; + Subsections &subsections = sections.back().subsections; + subsections.reserve(data.size() / recordSize); + auto *isec = make<ConcatInputSection>( + segname, name, this, data.slice(0, recordSize), align, flags); + subsections.push_back({0, isec}); + for (uint64_t off = recordSize; off < data.size(); off += recordSize) { + // Copying requires less memory than constructing a fresh InputSection. + auto *copy = make<ConcatInputSection>(*isec); + copy->data = data.slice(off, recordSize); + subsections.push_back({off, copy}); + } + }; + if (sectionType(sec.flags) == S_CSTRING_LITERALS || (config->dedupLiterals && isWordLiteralSection(sec.flags))) { if (sec.nreloc && config->dedupLiterals) @@ -267,31 +318,34 @@ void ObjFile::parseSections(ArrayRef<Section> sections) { isec = make<WordLiteralInputSection>(segname, name, this, data, align, flags); } - subsections.push_back({{0, isec}}); - } else if (config->icfLevel != ICFLevel::none && - (name == section_names::cfString && - segname == segment_names::data)) { - uint64_t literalSize = target->wordSize == 8 ? 32 : 16; - subsections.push_back({}); - SubsectionMap &subsecMap = subsections.back(); - for (uint64_t off = 0; off < data.size(); off += literalSize) - subsecMap.push_back( - {off, make<ConcatInputSection>(segname, name, this, - data.slice(off, literalSize), align, - flags)}); + sections.push_back(sec.addr); + sections.back().subsections.push_back({0, isec}); + } else if (auto recordSize = getRecordSize(segname, name)) { + splitRecords(*recordSize); + if (name == section_names::compactUnwind) + compactUnwindSection = §ions.back(); + } else if (segname == segment_names::llvm) { + // ld64 does not appear to emit contents from sections within the __LLVM + // segment. Symbols within those sections point to bitcode metadata + // instead of actual symbols. Global symbols within those sections could + // have the same name without causing duplicate symbol errors. Push an + // empty entry to ensure indices line up for the remaining sections. + // TODO: Evaluate whether the bitcode metadata is needed. + sections.push_back(sec.addr); } else { auto *isec = make<ConcatInputSection>(segname, name, this, data, align, flags); - if (!(isDebugSection(isec->getFlags()) && - isec->getSegName() == segment_names::dwarf)) { - subsections.push_back({{0, isec}}); - } else { + if (isDebugSection(isec->getFlags()) && + isec->getSegName() == segment_names::dwarf) { // Instead of emitting DWARF sections, we emit STABS symbols to the // object files that contain them. We filter them out early to avoid // parsing their relocations unnecessarily. But we must still push an - // empty map to ensure the indices line up for the remaining sections. - subsections.push_back({}); + // empty entry to ensure the indices line up for the remaining sections. + sections.push_back(sec.addr); debugSections.push_back(isec); + } else { + sections.push_back(sec.addr); + sections.back().subsections.push_back({0, isec}); } } } @@ -304,18 +358,21 @@ void ObjFile::parseSections(ArrayRef<Section> sections) { // any subsection splitting has occurred). It will be updated to represent the // same location as an offset relative to the start of the containing // subsection. -static InputSection *findContainingSubsection(SubsectionMap &map, - uint64_t *offset) { +template <class T> +static InputSection *findContainingSubsection(const Subsections &subsections, + T *offset) { + static_assert(std::is_same<uint64_t, T>::value || + std::is_same<uint32_t, T>::value, + "unexpected type for offset"); auto it = std::prev(llvm::upper_bound( - map, *offset, [](uint64_t value, SubsectionEntry subsecEntry) { - return value < subsecEntry.offset; - })); + subsections, *offset, + [](uint64_t value, Subsection subsec) { return value < subsec.offset; })); *offset -= it->offset; return it->isec; } -template <class Section> -static bool validateRelocationInfo(InputFile *file, const Section &sec, +template <class SectionHeader> +static bool validateRelocationInfo(InputFile *file, const SectionHeader &sec, relocation_info rel) { const RelocAttrs &relocAttrs = target->getRelocAttrs(rel.r_type); bool valid = true; @@ -346,14 +403,15 @@ static bool validateRelocationInfo(InputFile *file, const Section &sec, return valid; } -template <class Section> -void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders, - const Section &sec, SubsectionMap &subsecMap) { +template <class SectionHeader> +void ObjFile::parseRelocations(ArrayRef<SectionHeader> sectionHeaders, + const SectionHeader &sec, + Subsections &subsections) { auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart()); ArrayRef<relocation_info> relInfos( reinterpret_cast<const relocation_info *>(buf + sec.reloff), sec.nreloc); - auto subsecIt = subsecMap.rbegin(); + auto subsecIt = subsections.rbegin(); for (size_t i = 0; i < relInfos.size(); i++) { // Paired relocations serve as Mach-O's method for attaching a // supplemental datum to a primary relocation record. ELF does not @@ -380,8 +438,17 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders, // and insert them. Storing addends in the instruction stream is // possible, but inconvenient and more costly at link time. - int64_t pairedAddend = 0; relocation_info relInfo = relInfos[i]; + bool isSubtrahend = + target->hasAttr(relInfo.r_type, RelocAttrBits::SUBTRAHEND); + if (isSubtrahend && StringRef(sec.sectname) == section_names::ehFrame) { + // __TEXT,__eh_frame only has symbols and SUBTRACTOR relocs when ld64 -r + // adds local "EH_Frame1" and "func.eh". Ignore them because they have + // gone unused by Mac OS since Snow Leopard (10.6), vintage 2009. + ++i; + continue; + } + int64_t pairedAddend = 0; if (target->hasAttr(relInfo.r_type, RelocAttrBits::ADDEND)) { pairedAddend = SignExtend64<24>(relInfo.r_symbolnum); relInfo = relInfos[++i]; @@ -392,8 +459,6 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders, if (relInfo.r_address & R_SCATTERED) fatal("TODO: Scattered relocations not supported"); - bool isSubtrahend = - target->hasAttr(relInfo.r_type, RelocAttrBits::SUBTRAHEND); int64_t embeddedAddend = target->getEmbeddedAddend(mb, sec.offset, relInfo); assert(!(embeddedAddend && pairedAddend)); int64_t totalAddend = pairedAddend + embeddedAddend; @@ -407,7 +472,8 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders, r.addend = isSubtrahend ? 0 : totalAddend; } else { assert(!isSubtrahend); - const Section &referentSec = sectionHeaders[relInfo.r_symbolnum - 1]; + const SectionHeader &referentSecHead = + sectionHeaders[relInfo.r_symbolnum - 1]; uint64_t referentOffset; if (relInfo.r_pcrel) { // The implicit addend for pcrel section relocations is the pcrel offset @@ -417,14 +483,16 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders, // have pcrel section relocations. We may want to factor this out into // the arch-specific .cpp file. assert(target->hasAttr(r.type, RelocAttrBits::BYTE4)); - referentOffset = - sec.addr + relInfo.r_address + 4 + totalAddend - referentSec.addr; + referentOffset = sec.addr + relInfo.r_address + 4 + totalAddend - + referentSecHead.addr; } else { // The addend for a non-pcrel relocation is its absolute address. - referentOffset = totalAddend - referentSec.addr; + referentOffset = totalAddend - referentSecHead.addr; } - SubsectionMap &referentSubsecMap = subsections[relInfo.r_symbolnum - 1]; - r.referent = findContainingSubsection(referentSubsecMap, &referentOffset); + Subsections &referentSubsections = + sections[relInfo.r_symbolnum - 1].subsections; + r.referent = + findContainingSubsection(referentSubsections, &referentOffset); r.addend = referentOffset; } @@ -434,14 +502,14 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders, // unsorted relocations (in `-r` mode), so we have a fallback for that // uncommon case. InputSection *subsec; - while (subsecIt != subsecMap.rend() && subsecIt->offset > r.offset) + while (subsecIt != subsections.rend() && subsecIt->offset > r.offset) ++subsecIt; - if (subsecIt == subsecMap.rend() || + if (subsecIt == subsections.rend() || subsecIt->offset + subsecIt->isec->getSize() <= r.offset) { - subsec = findContainingSubsection(subsecMap, &r.offset); + subsec = findContainingSubsection(subsections, &r.offset); // Now that we know the relocs are unsorted, avoid trying the 'fast path' // for the other relocations. - subsecIt = subsecMap.rend(); + subsecIt = subsections.rend(); } else { subsec = subsecIt->isec; r.offset -= subsecIt->offset; @@ -462,10 +530,10 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders, } else { uint64_t referentOffset = totalAddend - sectionHeaders[minuendInfo.r_symbolnum - 1].addr; - SubsectionMap &referentSubsecMap = - subsections[minuendInfo.r_symbolnum - 1]; + Subsections &referentSubsectVec = + sections[minuendInfo.r_symbolnum - 1].subsections; p.referent = - findContainingSubsection(referentSubsecMap, &referentOffset); + findContainingSubsection(referentSubsectVec, &referentOffset); p.addend = referentOffset; } subsec->relocs.push_back(p); @@ -520,18 +588,23 @@ static macho::Symbol *createDefined(const NList &sym, StringRef name, // with ld64's semantics, because it means the non-private-extern // definition will continue to take priority if more private extern // definitions are encountered. With lld's semantics there's no observable - // difference between a symbol that's isWeakDefCanBeHidden or one that's - // privateExtern -- neither makes it into the dynamic symbol table. So just - // promote isWeakDefCanBeHidden to isPrivateExtern here. - if (isWeakDefCanBeHidden) + // difference between a symbol that's isWeakDefCanBeHidden(autohide) or one + // that's privateExtern -- neither makes it into the dynamic symbol table, + // unless the autohide symbol is explicitly exported. + // But if a symbol is both privateExtern and autohide then it can't + // be exported. + // So we nullify the autohide flag when privateExtern is present + // and promote the symbol to privateExtern when it is not already. + if (isWeakDefCanBeHidden && isPrivateExtern) + isWeakDefCanBeHidden = false; + else if (isWeakDefCanBeHidden) isPrivateExtern = true; - return symtab->addDefined( name, isec->getFile(), isec, value, size, sym.n_desc & N_WEAK_DEF, isPrivateExtern, sym.n_desc & N_ARM_THUMB_DEF, - sym.n_desc & REFERENCED_DYNAMICALLY, sym.n_desc & N_NO_DEAD_STRIP); + sym.n_desc & REFERENCED_DYNAMICALLY, sym.n_desc & N_NO_DEAD_STRIP, + isWeakDefCanBeHidden); } - assert(!isWeakDefCanBeHidden && "weak_def_can_be_hidden on already-hidden symbol?"); return make<Defined>( @@ -550,7 +623,8 @@ static macho::Symbol *createAbsolute(const NList &sym, InputFile *file, return symtab->addDefined( name, file, nullptr, sym.n_value, /*size=*/0, /*isWeakDef=*/false, sym.n_type & N_PEXT, sym.n_desc & N_ARM_THUMB_DEF, - /*isReferencedDynamically=*/false, sym.n_desc & N_NO_DEAD_STRIP); + /*isReferencedDynamically=*/false, sym.n_desc & N_NO_DEAD_STRIP, + /*isWeakDefCanBeHidden=*/false); } return make<Defined>(name, file, nullptr, sym.n_value, /*size=*/0, /*isWeakDef=*/false, @@ -585,8 +659,7 @@ macho::Symbol *ObjFile::parseNonSectionSymbol(const NList &sym, } } -template <class NList> -static bool isUndef(const NList &sym) { +template <class NList> static bool isUndef(const NList &sym) { return (sym.n_type & N_TYPE) == N_UNDF && sym.n_value == 0; } @@ -597,7 +670,7 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders, using NList = typename LP::nlist; // Groups indices of the symbols by the sections that contain them. - std::vector<std::vector<uint32_t>> symbolsBySection(subsections.size()); + std::vector<std::vector<uint32_t>> symbolsBySection(sections.size()); symbols.resize(nList.size()); SmallVector<unsigned, 32> undefineds; for (uint32_t i = 0; i < nList.size(); ++i) { @@ -610,9 +683,9 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders, StringRef name = strtab + sym.n_strx; if ((sym.n_type & N_TYPE) == N_SECT) { - SubsectionMap &subsecMap = subsections[sym.n_sect - 1]; + Subsections &subsections = sections[sym.n_sect - 1].subsections; // parseSections() may have chosen not to parse this section. - if (subsecMap.empty()) + if (subsections.empty()) continue; symbolsBySection[sym.n_sect - 1].push_back(i); } else if (isUndef(sym)) { @@ -622,28 +695,34 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders, } } - for (size_t i = 0; i < subsections.size(); ++i) { - SubsectionMap &subsecMap = subsections[i]; - if (subsecMap.empty()) + for (size_t i = 0; i < sections.size(); ++i) { + Subsections &subsections = sections[i].subsections; + if (subsections.empty()) continue; - + InputSection *lastIsec = subsections.back().isec; + if (lastIsec->getName() == section_names::ehFrame) { + // __TEXT,__eh_frame only has symbols and SUBTRACTOR relocs when ld64 -r + // adds local "EH_Frame1" and "func.eh". Ignore them because they have + // gone unused by Mac OS since Snow Leopard (10.6), vintage 2009. + continue; + } std::vector<uint32_t> &symbolIndices = symbolsBySection[i]; uint64_t sectionAddr = sectionHeaders[i].addr; uint32_t sectionAlign = 1u << sectionHeaders[i].align; - InputSection *isec = subsecMap.back().isec; - // __cfstring has already been split into subsections during + // Record-based sections have already been split into subsections during // parseSections(), so we simply need to match Symbols to the corresponding // subsection here. - if (config->icfLevel != ICFLevel::none && isCfStringSection(isec)) { + if (getRecordSize(lastIsec->getSegName(), lastIsec->getName())) { for (size_t j = 0; j < symbolIndices.size(); ++j) { uint32_t symIndex = symbolIndices[j]; const NList &sym = nList[symIndex]; StringRef name = strtab + sym.n_strx; uint64_t symbolOffset = sym.n_value - sectionAddr; - InputSection *isec = findContainingSubsection(subsecMap, &symbolOffset); + InputSection *isec = + findContainingSubsection(subsections, &symbolOffset); if (symbolOffset != 0) { - error(toString(this) + ": __cfstring contains symbol " + name + + error(toString(lastIsec) + ": symbol " + name + " at misaligned offset"); continue; } @@ -654,19 +733,19 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders, // Calculate symbol sizes and create subsections by splitting the sections // along symbol boundaries. - // We populate subsecMap by repeatedly splitting the last (highest address) - // subsection. + // We populate subsections by repeatedly splitting the last (highest + // address) subsection. llvm::stable_sort(symbolIndices, [&](uint32_t lhs, uint32_t rhs) { return nList[lhs].n_value < nList[rhs].n_value; }); - SubsectionEntry subsecEntry = subsecMap.back(); for (size_t j = 0; j < symbolIndices.size(); ++j) { uint32_t symIndex = symbolIndices[j]; const NList &sym = nList[symIndex]; StringRef name = strtab + sym.n_strx; - InputSection *isec = subsecEntry.isec; + Subsection &subsec = subsections.back(); + InputSection *isec = subsec.isec; - uint64_t subsecAddr = sectionAddr + subsecEntry.offset; + uint64_t subsecAddr = sectionAddr + subsec.offset; size_t symbolOffset = sym.n_value - subsecAddr; uint64_t symbolSize = j + 1 < symbolIndices.size() @@ -688,7 +767,6 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders, auto *concatIsec = cast<ConcatInputSection>(isec); auto *nextIsec = make<ConcatInputSection>(*concatIsec); - nextIsec->numRefs = 0; nextIsec->wasCoalesced = false; if (isZeroFill(isec->getFlags())) { // Zero-fill sections have NULL data.data() non-zero data.size() @@ -707,8 +785,7 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders, // subsection's offset from the last aligned address. We should consider // emulating that behavior. nextIsec->align = MinAlign(sectionAlign, sym.n_value); - subsecMap.push_back({sym.n_value - sectionAddr, nextIsec}); - subsecEntry = subsecMap.back(); + subsections.push_back({sym.n_value - sectionAddr, nextIsec}); } } @@ -734,7 +811,8 @@ OpaqueFile::OpaqueFile(MemoryBufferRef mb, StringRef segName, make<ConcatInputSection>(segName.take_front(16), sectName.take_front(16), /*file=*/this, data); isec->live = true; - subsections.push_back({{0, isec}}); + sections.push_back(0); + sections.back().subsections.push_back({0, isec}); } ObjFile::ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName) @@ -749,7 +827,7 @@ ObjFile::ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName) template <class LP> void ObjFile::parse() { using Header = typename LP::mach_header; using SegmentCommand = typename LP::segment_command; - using Section = typename LP::section; + using SectionHeader = typename LP::section; using NList = typename LP::nlist; auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart()); @@ -757,9 +835,12 @@ template <class LP> void ObjFile::parse() { Architecture arch = getArchitectureFromCpuType(hdr->cputype, hdr->cpusubtype); if (arch != config->arch()) { - error(toString(this) + " has architecture " + getArchitectureName(arch) + - " which is incompatible with target architecture " + - getArchitectureName(config->arch())); + auto msg = config->errorForArchMismatch + ? static_cast<void (*)(const Twine &)>(error) + : warn; + msg(toString(this) + " has architecture " + getArchitectureName(arch) + + " which is incompatible with target architecture " + + getArchitectureName(config->arch())); return; } @@ -772,11 +853,11 @@ template <class LP> void ObjFile::parse() { parseLCLinkerOption(this, cmd->count, data); } - ArrayRef<Section> sectionHeaders; + ArrayRef<SectionHeader> sectionHeaders; if (const load_command *cmd = findCommand(hdr, LP::segmentLCType)) { auto *c = reinterpret_cast<const SegmentCommand *>(cmd); - sectionHeaders = - ArrayRef<Section>{reinterpret_cast<const Section *>(c + 1), c->nsects}; + sectionHeaders = ArrayRef<SectionHeader>{ + reinterpret_cast<const SectionHeader *>(c + 1), c->nsects}; parseSections(sectionHeaders); } @@ -792,13 +873,16 @@ template <class LP> void ObjFile::parse() { // The relocations may refer to the symbols, so we parse them after we have // parsed all the symbols. - for (size_t i = 0, n = subsections.size(); i < n; ++i) - if (!subsections[i].empty()) - parseRelocations(sectionHeaders, sectionHeaders[i], subsections[i]); + for (size_t i = 0, n = sections.size(); i < n; ++i) + if (!sections[i].subsections.empty()) + parseRelocations(sectionHeaders, sectionHeaders[i], + sections[i].subsections); parseDebugInfo(); if (config->emitDataInCodeInfo) parseDataInCode(); + if (compactUnwindSection) + registerCompactUnwind(); } void ObjFile::parseDebugInfo() { @@ -839,6 +923,68 @@ void ObjFile::parseDataInCode() { })); } +// Create pointers from symbols to their associated compact unwind entries. +void ObjFile::registerCompactUnwind() { + for (const Subsection &subsection : compactUnwindSection->subsections) { + ConcatInputSection *isec = cast<ConcatInputSection>(subsection.isec); + // Hack!! Since each CUE contains a different function address, if ICF + // operated naively and compared the entire contents of each CUE, entries + // with identical unwind info but belonging to different functions would + // never be considered equivalent. To work around this problem, we slice + // away the function address here. (Note that we do not adjust the offsets + // of the corresponding relocations.) We rely on `relocateCompactUnwind()` + // to correctly handle these truncated input sections. + isec->data = isec->data.slice(target->wordSize); + + ConcatInputSection *referentIsec; + for (auto it = isec->relocs.begin(); it != isec->relocs.end();) { + Reloc &r = *it; + // CUE::functionAddress is at offset 0. Skip personality & LSDA relocs. + if (r.offset != 0) { + ++it; + continue; + } + uint64_t add = r.addend; + if (auto *sym = cast_or_null<Defined>(r.referent.dyn_cast<Symbol *>())) { + // Check whether the symbol defined in this file is the prevailing one. + // Skip if it is e.g. a weak def that didn't prevail. + if (sym->getFile() != this) { + ++it; + continue; + } + add += sym->value; + referentIsec = cast<ConcatInputSection>(sym->isec); + } else { + referentIsec = + cast<ConcatInputSection>(r.referent.dyn_cast<InputSection *>()); + } + if (referentIsec->getSegName() != segment_names::text) + error("compact unwind references address in " + toString(referentIsec) + + " which is not in segment __TEXT"); + // The functionAddress relocations are typically section relocations. + // However, unwind info operates on a per-symbol basis, so we search for + // the function symbol here. + auto symIt = llvm::lower_bound( + referentIsec->symbols, add, + [](Defined *d, uint64_t add) { return d->value < add; }); + // The relocation should point at the exact address of a symbol (with no + // addend). + if (symIt == referentIsec->symbols.end() || (*symIt)->value != add) { + assert(referentIsec->wasCoalesced); + ++it; + continue; + } + (*symIt)->unwindEntry = isec; + // Since we've sliced away the functionAddress, we should remove the + // corresponding relocation too. Given that clang emits relocations in + // reverse order of address, this relocation should be at the end of the + // vector for most of our input object files, so this is typically an O(1) + // operation. + it = isec->relocs.erase(it); + } + } +} + // The path can point to either a dylib or a .tbd file. static DylibFile *loadDylib(StringRef path, DylibFile *umbrella) { Optional<MemoryBufferRef> mbref = readFile(path); @@ -871,7 +1017,7 @@ static DylibFile *findDylib(StringRef path, DylibFile *umbrella, for (StringRef dir : config->frameworkSearchPaths) { SmallString<128> candidate = dir; path::append(candidate, frameworkName); - if (Optional<std::string> dylibPath = resolveDylibPath(candidate)) + if (Optional<StringRef> dylibPath = resolveDylibPath(candidate.str())) return loadDylib(*dylibPath, umbrella); } } else if (Optional<StringRef> dylibPath = findPathCombination( @@ -882,8 +1028,7 @@ static DylibFile *findDylib(StringRef path, DylibFile *umbrella, // 2. As absolute path. if (path::is_absolute(path, path::Style::posix)) for (StringRef root : config->systemLibraryRoots) - if (Optional<std::string> dylibPath = - resolveDylibPath((root + path).str())) + if (Optional<StringRef> dylibPath = resolveDylibPath((root + path).str())) return loadDylib(*dylibPath, umbrella); // 3. As relative path. @@ -912,7 +1057,7 @@ static DylibFile *findDylib(StringRef path, DylibFile *umbrella, path::remove_filename(newPath); } path::append(newPath, rpath, path.drop_front(strlen("@rpath/"))); - if (Optional<std::string> dylibPath = resolveDylibPath(newPath)) + if (Optional<StringRef> dylibPath = resolveDylibPath(newPath.str())) return loadDylib(*dylibPath, umbrella); } } @@ -930,7 +1075,7 @@ static DylibFile *findDylib(StringRef path, DylibFile *umbrella, } } - if (Optional<std::string> dylibPath = resolveDylibPath(path)) + if (Optional<StringRef> dylibPath = resolveDylibPath(path)) return loadDylib(*dylibPath, umbrella); return nullptr; @@ -1129,7 +1274,7 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella, void DylibFile::parseReexports(const InterfaceFile &interface) { const InterfaceFile *topLevel = interface.getParent() == nullptr ? &interface : interface.getParent(); - for (InterfaceFileRef intfRef : interface.reexportedLibraries()) { + for (const InterfaceFileRef &intfRef : interface.reexportedLibraries()) { InterfaceFile::const_target_range targets = intfRef.targets(); if (is_contained(skipPlatformChecks, intfRef.getInstallName()) || is_contained(targets, config->platformInfo.target)) @@ -1225,47 +1370,75 @@ void DylibFile::checkAppExtensionSafety(bool dylibIsAppExtensionSafe) const { } ArchiveFile::ArchiveFile(std::unique_ptr<object::Archive> &&f) - : InputFile(ArchiveKind, f->getMemoryBufferRef()), file(std::move(f)) { + : InputFile(ArchiveKind, f->getMemoryBufferRef()), file(std::move(f)) {} + +void ArchiveFile::addLazySymbols() { for (const object::Archive::Symbol &sym : file->symbols()) symtab->addLazy(sym.getName(), this, sym); } -void ArchiveFile::fetch(const object::Archive::Symbol &sym) { - object::Archive::Child c = - CHECK(sym.getMember(), toString(this) + - ": could not get the member for symbol " + - toMachOString(sym)); +static Expected<InputFile *> loadArchiveMember(MemoryBufferRef mb, + uint32_t modTime, + StringRef archiveName, + uint64_t offsetInArchive) { + if (config->zeroModTime) + modTime = 0; + switch (identify_magic(mb.getBuffer())) { + case file_magic::macho_object: + return make<ObjFile>(mb, modTime, archiveName); + case file_magic::bitcode: + return make<BitcodeFile>(mb, archiveName, offsetInArchive); + default: + return createStringError(inconvertibleErrorCode(), + mb.getBufferIdentifier() + + " has unhandled file type"); + } +} + +Error ArchiveFile::fetch(const object::Archive::Child &c, StringRef reason) { if (!seen.insert(c.getChildOffset()).second) - return; + return Error::success(); - MemoryBufferRef mb = - CHECK(c.getMemoryBufferRef(), - toString(this) + - ": could not get the buffer for the member defining symbol " + - toMachOString(sym)); + Expected<MemoryBufferRef> mb = c.getMemoryBufferRef(); + if (!mb) + return mb.takeError(); + // Thin archives refer to .o files, so --reproduce needs the .o files too. if (tar && c.getParent()->isThin()) - tar->append(relativeToRoot(CHECK(c.getFullName(), this)), mb.getBuffer()); + tar->append(relativeToRoot(CHECK(c.getFullName(), this)), mb->getBuffer()); + + Expected<TimePoint<std::chrono::seconds>> modTime = c.getLastModified(); + if (!modTime) + return modTime.takeError(); + + Expected<InputFile *> file = + loadArchiveMember(*mb, toTimeT(*modTime), getName(), c.getChildOffset()); + + if (!file) + return file.takeError(); + + inputFiles.insert(*file); + printArchiveMemberLoad(reason, *file); + return Error::success(); +} - uint32_t modTime = toTimeT( - CHECK(c.getLastModified(), toString(this) + - ": could not get the modification time " - "for the member defining symbol " + - toMachOString(sym))); +void ArchiveFile::fetch(const object::Archive::Symbol &sym) { + object::Archive::Child c = + CHECK(sym.getMember(), toString(this) + + ": could not get the member defining symbol " + + toMachOString(sym)); // `sym` is owned by a LazySym, which will be replace<>()d by make<ObjFile> // and become invalid after that call. Copy it to the stack so we can refer // to it later. const object::Archive::Symbol symCopy = sym; - if (Optional<InputFile *> file = loadArchiveMember( - mb, modTime, getName(), /*objCOnly=*/false, c.getChildOffset())) { - inputFiles.insert(*file); - // ld64 doesn't demangle sym here even with -demangle. - // Match that: intentionally don't call toMachOString(). - printArchiveMemberLoad(symCopy.getName(), *file); - } + // ld64 doesn't demangle sym here even with -demangle. + // Match that: intentionally don't call toMachOString(). + if (Error e = fetch(c, symCopy.getName())) + error(toString(this) + ": could not get the member defining symbol " + + toMachOString(symCopy) + ": " + toString(std::move(e))); } static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym, @@ -1276,8 +1449,6 @@ static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym, if (objSym.isUndefined()) return symtab->addUndefined(name, &file, /*isWeakRef=*/false); - assert(!objSym.isCommon() && "TODO: support common symbols in LTO"); - // TODO: Write a test demonstrating why computing isPrivateExtern before // LTO compilation is important. bool isPrivateExtern = false; @@ -1292,11 +1463,16 @@ static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym, break; } + if (objSym.isCommon()) + return symtab->addCommon(name, &file, objSym.getCommonSize(), + objSym.getCommonAlignment(), isPrivateExtern); + return symtab->addDefined(name, &file, /*isec=*/nullptr, /*value=*/0, /*size=*/0, objSym.isWeak(), isPrivateExtern, /*isThumb=*/false, /*isReferencedDynamically=*/false, - /*noDeadStrip=*/false); + /*noDeadStrip=*/false, + /*isWeakDefCanBeHidden=*/false); } BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName, |
