Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -84,6 +84,7 @@ uint8_t OSABI = 0; llvm::CachePruningPolicy ThinLTOCachePolicy; llvm::StringMap SectionStartMap; + llvm::StringRef BuildIdLinkDir; llvm::StringRef Chroot; llvm::StringRef DynamicLinker; llvm::StringRef DwoDir; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -730,6 +730,7 @@ Config->AuxiliaryList = args::getStrings(Args, OPT_auxiliary); Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); + Config->BuildIdLinkDir = Args.getLastArgValue(OPT_build_id_link_dir); Config->CheckSections = Args.hasFlag(OPT_check_sections, OPT_no_check_sections, true); Config->Chroot = Args.getLastArgValue(OPT_chroot); Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -32,6 +32,11 @@ def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">, MetaVarName<"[fast,md5,sha,uuid,0x]">; +defm build_id_link_dir: + Eq<"build-id-link-dir", + "Hard-link output to /xx/xxx name derived from hex build ID">, + MetaVarName<"">; + defm check_sections: B<"check-sections", "Check section addresses for overlaps (default)", "Do not check section addresses for overlaps">; Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -153,7 +153,7 @@ BuildIdSection(); void writeTo(uint8_t *Buf) override; size_t getSize() const override { return HeaderSize + HashSize; } - void writeBuildId(llvm::ArrayRef Buf); + llvm::SmallVector writeBuildId(llvm::ArrayRef Buf); private: void computeHash(llvm::ArrayRef Buf, Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -331,7 +331,8 @@ this->Size = Size; } -void BuildIdSection::writeBuildId(ArrayRef Buf) { +llvm::SmallVector +BuildIdSection::writeBuildId(ArrayRef Buf) { switch (Config->BuildId) { case BuildIdKind::Fast: computeHash(Buf, [](uint8_t *Dest, ArrayRef Arr) { @@ -358,6 +359,7 @@ default: llvm_unreachable("unknown BuildIdKind"); } + return {HashBuf, HashBuf + HashSize}; } EhFrameSection::EhFrameSection() Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -25,6 +25,7 @@ #include "lld/Common/Threads.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Path.h" #include using namespace llvm; @@ -71,6 +72,7 @@ void writeSections(); void writeSectionsBinary(); void writeBuildId(); + void writeBuildIdLink(); std::unique_ptr &Buffer; @@ -83,6 +85,8 @@ uint64_t FileSize; uint64_t SectionHeaderOff; + + SmallVector BuildIdBytes; }; } // anonymous namespace @@ -522,6 +526,8 @@ if (auto E = Buffer->commit()) error("failed to write to the output file: " + toString(std::move(E))); + + writeBuildIdLink(); } static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName, @@ -2411,7 +2417,42 @@ // Compute a hash of all sections of the output file. uint8_t *Start = Buffer->getBufferStart(); uint8_t *End = Start + FileSize; - InX::BuildId->writeBuildId({Start, End}); + BuildIdBytes = InX::BuildId->writeBuildId({Start, End}); +} + +template void Writer::writeBuildIdLink() { + if (Config->BuildIdLinkDir.empty() || + !InX::BuildId || !InX::BuildId->getParent()) + return; + + if (BuildIdBytes.size() < 2) { + error("build ID too small for --build-id-link-dir"); + return; + } + + char HexByteStrBuf[3]; + const auto HexDigit = "0123456789abcdef"; + auto HexByteStr = [&](uint8_t x) -> char* { + HexByteStrBuf[0] = HexDigit[x >> 4]; + HexByteStrBuf[1] = HexDigit[x & 0xf]; + HexByteStrBuf[2] = '\0'; + return HexByteStrBuf; + }; + + SmallString<128> Path(Config->BuildIdLinkDir); + llvm::sys::path::append(Path, HexByteStr(BuildIdBytes[0])); + if (auto EC = sys::fs::create_directories(Path)) { + error("cannot create build ID link directory " + + Path + ": " + EC.message()); + return; + } + + llvm::sys::path::append(Path, HexByteStr(BuildIdBytes[1])); + for (auto It = BuildIdBytes.begin() + 2; It != BuildIdBytes.end(); ++It) + Path.append(HexByteStr(*It)); + + if (auto EC = sys::fs::create_hard_link(Config->OutputFile, Path)) + error("cannot link " + Path + ": " + EC.message()); } template void elf::writeResult();