Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -54,6 +54,7 @@ bool AsNeeded = false; bool Bsymbolic; bool BsymbolicFunctions; + bool BuildId; bool Demangle = true; bool DiscardAll; bool DiscardLocals; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -223,6 +223,7 @@ Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition); Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); + Config->BuildId = Args.hasArg(OPT_build_id); Config->Demangle = !Args.hasArg(OPT_no_demangle); Config->DiscardAll = Args.hasArg(OPT_discard_all); Config->DiscardLocals = Args.hasArg(OPT_discard_locals); Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -12,6 +12,8 @@ def Bstatic: Flag<["-"], "Bstatic">, HelpText<"Do not link against shared libraries">; +def build_id : Flag<["--"], "build-id">; + def L : JoinedOrSeparate<["-"], "L">, MetaVarName<"">, HelpText<"Directory to search for libraries">; @@ -170,7 +172,6 @@ def start_group_paren: Flag<["-"], "(">; // Options listed below are silently ignored for now for compatibility. -def build_id : Flag<["--"], "build-id">; def fatal_warnings : Flag<["--"], "fatal-warnings">; def no_add_needed : Flag<["--"], "no-add-needed">; def no_fatal_warnings : Flag<["--"], "no-fatal-warnings">; Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -14,6 +14,7 @@ #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELF.h" +#include "llvm/Support/MD5.h" #include "Config.h" @@ -529,12 +530,26 @@ std::vector FdeList; }; +template +class BuildIdSection final : public OutputSectionBase { +public: + BuildIdSection(); + void writeTo(uint8_t *Buf) override; + void update(ArrayRef Buf); + void writeBuildId(); + +private: + llvm::MD5 Hash; + uint8_t *Md5Buf; +}; + // All output sections that are hadnled by the linker specially are // globally accessible. Writer initializes them, so don't use them // until Writer is initialized. template struct Out { typedef typename llvm::object::ELFFile::uintX_t uintX_t; typedef typename llvm::object::ELFFile::Elf_Phdr Elf_Phdr; + static BuildIdSection *BuildId; static DynamicSection *Dynamic; static EhFrameHeader *EhFrameHdr; static GnuHashTableSection *GnuHashTab; @@ -559,6 +574,7 @@ static OutputSectionBase *ProgramHeaders; }; +template BuildIdSection *Out::BuildId; template DynamicSection *Out::Dynamic; template EhFrameHeader *Out::EhFrameHdr; template GnuHashTableSection *Out::GnuHashTab; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -1566,6 +1566,32 @@ } template +BuildIdSection::BuildIdSection() + : OutputSectionBase(".note.gnu.build-id", SHT_NOTE, 0) { + // 16 bytes for the note section header and 16 bytes for MD5. + this->Header.sh_size = 32; +} + +template void BuildIdSection::writeTo(uint8_t *Buf) { + const endianness E = ELFT::TargetEndianness; + write32(Buf, 4); // Name size + write32(Buf + 4, 16); // Content size + write32(Buf + 8, 3); // Type (NT_GNU_BUILD_ID = 3) + memcpy(Buf + 12, "GNU", 4); // Name string + Md5Buf = Buf + 16; +} + +template void BuildIdSection::update(ArrayRef Buf) { + Hash.update(Buf); +} + +template void BuildIdSection::writeBuildId() { + MD5::MD5Result Res; + Hash.final(Res); + memcpy(Md5Buf, Res, 16); +} + +template MipsReginfoOutputSection::MipsReginfoOutputSection() : OutputSectionBase(".reginfo", SHT_MIPS_REGINFO, SHF_ALLOC) { this->Header.sh_addralign = 4; @@ -1669,6 +1695,11 @@ template class SymbolTableSection; template class SymbolTableSection; +template class BuildIdSection; +template class BuildIdSection; +template class BuildIdSection; +template class BuildIdSection; + template uint32_t getLocalRelTarget(const ObjectFile &, const ELFFile::Elf_Rel &, uint32_t); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -75,6 +75,7 @@ bool openFile(); void writeHeader(); void writeSections(); + void writeBuildId(); bool isDiscarded(InputSectionBase *IS) const; StringRef getOutputSectionName(InputSectionBase *S) const; bool needsInterpSection() const { @@ -143,6 +144,7 @@ ProgramHeaders.updateAlign(sizeof(uintX_t)); // Instantiate optional output sections if they are needed. + std::unique_ptr> BuildId; std::unique_ptr> GnuHashTab; std::unique_ptr> GotPlt; std::unique_ptr> HashTab; @@ -151,6 +153,8 @@ std::unique_ptr> SymTabSec; std::unique_ptr> MipsRldMap; + if (Config->BuildId) + BuildId.reset(new BuildIdSection); if (Config->GnuHash) GnuHashTab.reset(new GnuHashTableSection); if (Config->SysvHash) @@ -175,6 +179,7 @@ MipsRldMap->updateAlign(sizeof(uintX_t)); } + Out::BuildId = BuildId.get(); Out::DynStrTab = &DynStrTab; Out::DynSymTab = &DynSymTab; Out::Dynamic = &Dynamic; @@ -221,6 +226,7 @@ writeSections(); if (HasError) return; + writeBuildId(); check(Buffer->commit()); } @@ -1126,6 +1132,7 @@ // This order is not the same as the final output order // because we sort the sections using their attributes below. + Add(Out::BuildId); Add(Out::SymTab); Add(Out::ShStrTab); Add(Out::StrTab); @@ -1547,6 +1554,29 @@ Sec->writeTo(Buf + Sec->getFileOff()); } +template void Writer::writeBuildId() { + BuildIdSection *S = Out::BuildId; + if (!S) + return; + + // Compute the md5sum of all sections except .debug_* sections. + // We skip debug sections because they tend to be very large + // and their contents are very likely to be the same as long as + // other sections are the same. + uint8_t *Start = Buffer->getBufferStart(); + uint8_t *Last = Start; + for (OutputSectionBase *Sec : OutputSections) { + uint8_t *End = Start + Sec->getFileOff(); + if (!Sec->getName().startswith(".debug_")) + S->update({Last, End}); + Last = End; + } + S->update({Last, Start + FileSize}); + + // Fill the MD5 field in the .note.gnu.build-id section. + S->writeBuildId(); +} + template void elf::writeResult(SymbolTable *Symtab); template void elf::writeResult(SymbolTable *Symtab); template void elf::writeResult(SymbolTable *Symtab);