diff options
Diffstat (limited to 'lld/MachO/Writer.cpp')
| -rw-r--r-- | lld/MachO/Writer.cpp | 73 |
1 files changed, 58 insertions, 15 deletions
diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp index 851cb3db3859..9395e1a068a3 100644 --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -20,6 +20,7 @@ #include "SyntheticSections.h" #include "Target.h" #include "UnwindInfoSection.h" +#include "llvm/Support/Parallel.h" #include "lld/Common/Arrays.h" #include "lld/Common/CommonLinkerContext.h" @@ -458,9 +459,11 @@ public: auto *c = reinterpret_cast<build_version_command *>(buf); c->cmd = LC_BUILD_VERSION; c->cmdsize = getSize(); + c->platform = static_cast<uint32_t>(platformInfo.target.Platform); c->minos = encodeVersion(platformInfo.minimum); c->sdk = encodeVersion(platformInfo.sdk); + c->ntools = ntools; auto *t = reinterpret_cast<build_tool_version *>(&c[1]); t->tool = TOOL_LD; @@ -594,6 +597,9 @@ static void prepareBranchTarget(Symbol *sym) { in.weakBinding->addEntry(sym, in.lazyPointers->isec, sym->stubsIndex * target->wordSize); } + } else if (defined->interposable) { + if (in.stubs->addEntry(sym)) + in.lazyBinding->addEntry(sym); } } else { llvm_unreachable("invalid branch target symbol type"); @@ -605,7 +611,7 @@ static bool needsBinding(const Symbol *sym) { if (isa<DylibSymbol>(sym)) return true; if (const auto *defined = dyn_cast<Defined>(sym)) - return defined->isExternalWeakDef(); + return defined->isExternalWeakDef() || defined->interposable; return false; } @@ -653,7 +659,7 @@ void Writer::scanRelocations() { } if (auto *sym = r.referent.dyn_cast<Symbol *>()) { if (auto *undefined = dyn_cast<Undefined>(sym)) - treatUndefinedSymbol(*undefined); + treatUndefinedSymbol(*undefined, isec, r.offset); // treatUndefinedSymbol() can replace sym with a DylibSymbol; re-check. if (!isa<Undefined>(sym) && validateSymbolRelocation(sym, isec, r)) prepareSymbolRelocation(sym, isec, r); @@ -765,6 +771,11 @@ template <class LP> void Writer::createLoadCommands() { else in.header->addLoadCommand(make<LCMinVersion>(config->platformInfo)); + if (config->secondaryPlatformInfo) { + in.header->addLoadCommand( + make<LCBuildVersion>(*config->secondaryPlatformInfo)); + } + // This is down here to match ld64's load command order. if (config->outputType == MH_EXECUTE) in.header->addLoadCommand(make<LCMain>()); @@ -857,7 +868,7 @@ static void sortSegmentsAndSections() { sortOutputSegments(); DenseMap<const InputSection *, size_t> isecPriorities = - buildInputSectionPriorities(); + priorityBuilder.buildInputSectionPriorities(); uint32_t sectionIndex = 0; for (OutputSegment *seg : outputSegments) { @@ -939,8 +950,14 @@ template <class LP> void Writer::createOutputSections() { StringRef segname = it.first.first; ConcatOutputSection *osec = it.second; assert(segname != segment_names::ld); - if (osec->isNeeded()) + if (osec->isNeeded()) { + // See comment in ObjFile::splitEhFrames() + if (osec->name == section_names::ehFrame && + segname == segment_names::text) + osec->align = target->wordSize; + getOrCreateOutputSegment(segname)->addOutputSection(osec); + } } for (SyntheticSection *ssec : syntheticSections) { @@ -969,6 +986,21 @@ template <class LP> void Writer::createOutputSections() { void Writer::finalizeAddresses() { TimeTraceScope timeScope("Finalize addresses"); uint64_t pageSize = target->getPageSize(); + + // We could parallelize this loop, but local benchmarking indicates it is + // faster to do it all in the main thread. + for (OutputSegment *seg : outputSegments) { + if (seg == linkEditSegment) + continue; + for (OutputSection *osec : seg->getSections()) { + if (!osec->isNeeded()) + continue; + // Other kinds of OutputSections have already been finalized. + if (auto concatOsec = dyn_cast<ConcatOutputSection>(osec)) + concatOsec->finalizeContents(); + } + } + // Ensure that segments (and the sections they contain) are allocated // addresses in ascending order, which dyld requires. // @@ -1048,17 +1080,21 @@ void Writer::openFile() { FileOutputBuffer::F_executable); if (!bufferOrErr) - error("failed to open " + config->outputFile + ": " + + fatal("failed to open " + config->outputFile + ": " + llvm::toString(bufferOrErr.takeError())); - else - buffer = std::move(*bufferOrErr); + buffer = std::move(*bufferOrErr); + in.bufferStart = buffer->getBufferStart(); } void Writer::writeSections() { uint8_t *buf = buffer->getBufferStart(); + std::vector<const OutputSection *> osecs; for (const OutputSegment *seg : outputSegments) - for (const OutputSection *osec : seg->getSections()) - osec->writeTo(buf + osec->fileOff); + append_range(osecs, seg->getSections()); + + parallelForEach(osecs.begin(), osecs.end(), [&](const OutputSection *osec) { + osec->writeTo(buf + osec->fileOff); + }); } // In order to utilize multiple cores, we first split the buffer into chunks, @@ -1072,7 +1108,8 @@ void Writer::writeUuid() { // Round-up integer division size_t chunkSize = (data.size() + chunkCount - 1) / chunkCount; std::vector<ArrayRef<uint8_t>> chunks = split(data, chunkSize); - std::vector<uint64_t> hashes(chunks.size()); + // Leave one slot for filename + std::vector<uint64_t> hashes(chunks.size() + 1); SmallVector<std::shared_future<void>> threadFutures; threadFutures.reserve(chunks.size()); for (size_t i = 0; i < chunks.size(); ++i) @@ -1080,20 +1117,25 @@ void Writer::writeUuid() { [&](size_t j) { hashes[j] = xxHash64(chunks[j]); }, i)); for (std::shared_future<void> &future : threadFutures) future.wait(); - + // Append the output filename so that identical binaries with different names + // don't get the same UUID. + hashes[chunks.size()] = xxHash64(sys::path::filename(config->finalOutput)); uint64_t digest = xxHash64({reinterpret_cast<uint8_t *>(hashes.data()), hashes.size() * sizeof(uint64_t)}); uuidCommand->writeUuid(digest); } void Writer::writeCodeSignature() { - if (codeSignatureSection) + if (codeSignatureSection) { + TimeTraceScope timeScope("Write code signature"); codeSignatureSection->writeHashes(buffer->getBufferStart()); + } } void Writer::writeOutputFile() { TimeTraceScope timeScope("Write output file"); openFile(); + reportPendingUndefinedSymbols(); if (errorCount()) return; writeSections(); @@ -1116,6 +1158,7 @@ template <class LP> void Writer::run() { scanRelocations(); // Do not proceed if there was an undefined symbol. + reportPendingUndefinedSymbols(); if (errorCount()) return; @@ -1172,10 +1215,10 @@ void macho::createSyntheticSections() { // dyld to cache an address to the image loader it uses. uint8_t *arr = bAlloc().Allocate<uint8_t>(target->wordSize); memset(arr, 0, target->wordSize); - in.imageLoaderCache = make<ConcatInputSection>( - segment_names::data, section_names::data, /*file=*/nullptr, + in.imageLoaderCache = makeSyntheticInputSection( + segment_names::data, section_names::data, S_REGULAR, ArrayRef<uint8_t>{arr, target->wordSize}, - /*align=*/target->wordSize, /*flags=*/S_REGULAR); + /*align=*/target->wordSize); // References from dyld are not visible to us, so ensure this section is // always treated as live. in.imageLoaderCache->live = true; |
