Index: llvm/tools/llvm-objcopy/CopyConfig.h =================================================================== --- llvm/tools/llvm-objcopy/CopyConfig.h +++ llvm/tools/llvm-objcopy/CopyConfig.h @@ -115,6 +115,8 @@ // Advanced options StringRef AddGnuDebugLink; + // Cached gnu_debuglink's target CRC + uint32_t GnuDebugLinkCRC32; StringRef BuildIdLinkDir; Optional BuildIdLinkInput; Optional BuildIdLinkOutput; Index: llvm/tools/llvm-objcopy/CopyConfig.cpp =================================================================== --- llvm/tools/llvm-objcopy/CopyConfig.cpp +++ llvm/tools/llvm-objcopy/CopyConfig.cpp @@ -16,6 +16,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Errc.h" +#include "llvm/Support/JamCRC.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/StringSaver.h" #include @@ -490,6 +491,22 @@ } Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink); + // The gnu_debuglink's target is expected to not change or else its CRC would + // become invalidated and get rejected. We can avoid recalculating the + // checksum for every target file inside an archive by precomputing the CRC + // here. This prevents a significant amount of I/O. + if (!Config.AddGnuDebugLink.empty()) { + auto DebugOrErr = MemoryBuffer::getFile(Config.AddGnuDebugLink); + if (!DebugOrErr) + return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError()); + auto Debug = std::move(*DebugOrErr); + JamCRC CRC; + CRC.update( + ArrayRef(Debug->getBuffer().data(), Debug->getBuffer().size())); + // The CRC32 value needs to be complemented because the JamCRC doesn't + // finalize the CRC32 value. + Config.GnuDebugLinkCRC32 = ~CRC.getCRC(); + } Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir); if (InputArgs.hasArg(OBJCOPY_build_id_link_input)) Config.BuildIdLinkInput = @@ -748,7 +765,8 @@ Config.SymbolsToKeep.emplace_back(Arg->getValue(), UseRegexp); if (!Config.StripDebug && !Config.StripUnneeded && - Config.DiscardMode == DiscardType::None && !Config.StripAllGNU && Config.SymbolsToRemove.empty()) + Config.DiscardMode == DiscardType::None && !Config.StripAllGNU && + Config.SymbolsToRemove.empty()) Config.StripAll = true; Config.DeterministicArchives = Index: llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp =================================================================== --- llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -629,7 +629,8 @@ } if (!Config.AddGnuDebugLink.empty()) - Obj.addSection(Config.AddGnuDebugLink); + Obj.addSection(Config.AddGnuDebugLink, + Config.GnuDebugLinkCRC32); for (const NewSymbolInfo &SI : Config.SymbolsToAdd) { SectionBase *Sec = Obj.findSection(SI.SectionName); Index: llvm/tools/llvm-objcopy/ELF/Object.h =================================================================== --- llvm/tools/llvm-objcopy/ELF/Object.h +++ llvm/tools/llvm-objcopy/ELF/Object.h @@ -18,7 +18,6 @@ #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/JamCRC.h" #include #include #include @@ -703,11 +702,11 @@ StringRef FileName; uint32_t CRC32; - void init(StringRef File, StringRef Data); + void init(StringRef File); public: // If we add this section from an external source we can use this ctor. - explicit GnuDebugLinkSection(StringRef File); + explicit GnuDebugLinkSection(StringRef File, uint32_t PrecomputedCRC); void accept(SectionVisitor &Visitor) const override; void accept(MutableSectionVisitor &Visitor) override; }; Index: llvm/tools/llvm-objcopy/ELF/Object.cpp =================================================================== --- llvm/tools/llvm-objcopy/ELF/Object.cpp +++ llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -755,7 +755,7 @@ void Section::finalize() { this->Link = LinkSection ? LinkSection->Index : 0; } -void GnuDebugLinkSection::init(StringRef File, StringRef Data) { +void GnuDebugLinkSection::init(StringRef File) { FileName = sys::path::filename(File); // The format for the .gnu_debuglink starts with the file name and is // followed by a null terminator and then the CRC32 of the file. The CRC32 @@ -770,21 +770,12 @@ // establish the order that sections should go in. By using the maximum // possible offset we cause this section to wind up at the end. OriginalOffset = std::numeric_limits::max(); - JamCRC CRC; - CRC.update(ArrayRef(Data.data(), Data.size())); - // The CRC32 value needs to be complemented because the JamCRC dosn't - // finalize the CRC32 value. It also dosn't negate the initial CRC32 value - // but it starts by default at 0xFFFFFFFF which is the complement of zero. - CRC32 = ~CRC.getCRC(); -} - -GnuDebugLinkSection::GnuDebugLinkSection(StringRef File) : FileName(File) { - // Read in the file to compute the CRC of it. - auto DebugOrErr = MemoryBuffer::getFile(File); - if (!DebugOrErr) - error("'" + File + "': " + DebugOrErr.getError().message()); - auto Debug = std::move(*DebugOrErr); - init(File, Debug->getBuffer()); +} + +GnuDebugLinkSection::GnuDebugLinkSection(StringRef File, + uint32_t PrecomputedCRC) + : FileName(File), CRC32(PrecomputedCRC) { + init(File); } template