bool AsNeeded = false;
bool Bsymbolic;
bool BsymbolicFunctions;
+ bool BuildId;
bool Demangle = true;
bool DiscardAll;
bool DiscardLocals;
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);
def Bstatic: Flag<["-"], "Bstatic">,
HelpText<"Do not link against shared libraries">;
+def build_id : Flag<["--", "-"], "build-id">,
+ HelpText<"Generate build ID note">;
+
def L : JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
HelpText<"Directory to search for libraries">;
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">;
}
template <class ELFT>
+BuildIdSection<ELFT>::BuildIdSection()
+ : OutputSectionBase<ELFT>(".note.gnu.build-id", SHT_NOTE, SHF_ALLOC) {
+ // 16 bytes for the note section header and 8 bytes for FNV1 hash.
+ this->Header.sh_size = 24;
+}
+
+template <class ELFT> void BuildIdSection<ELFT>::writeTo(uint8_t *Buf) {
+ const endianness E = ELFT::TargetEndianness;
+ write32<E>(Buf, 4); // Name size
+ write32<E>(Buf + 4, sizeof(Hash)); // Content size
+ write32<E>(Buf + 8, NT_GNU_BUILD_ID); // Type
+ memcpy(Buf + 12, "GNU", 4); // Name string
+ HashBuf = Buf + 16;
+}
+
+template <class ELFT> void BuildIdSection<ELFT>::update(ArrayRef<uint8_t> Buf) {
+ // 64-bit FNV1 hash
+ const uint64_t Prime = 0x100000001b3;
+ for (uint8_t B : Buf) {
+ Hash *= Prime;
+ Hash ^= B;
+ }
+}
+
+template <class ELFT> void BuildIdSection<ELFT>::writeBuildId() {
+ const endianness E = ELFT::TargetEndianness;
+ write64<E>(HashBuf, Hash);
+}
+
+template <class ELFT>
MipsReginfoOutputSection<ELFT>::MipsReginfoOutputSection()
: OutputSectionBase<ELFT>(".reginfo", SHT_MIPS_REGINFO, SHF_ALLOC) {
this->Header.sh_addralign = 4;
template class SymbolTableSection<ELF32BE>;
template class SymbolTableSection<ELF64LE>;
template class SymbolTableSection<ELF64BE>;
+
+template class BuildIdSection<ELF32LE>;
+template class BuildIdSection<ELF32BE>;
+template class BuildIdSection<ELF64LE>;
+template class BuildIdSection<ELF64BE>;
}
}
std::vector<FdeData> FdeList;
};
+template <class ELFT>
+class BuildIdSection final : public OutputSectionBase<ELFT> {
+public:
+ BuildIdSection();
+ void writeTo(uint8_t *Buf) override;
+ void update(ArrayRef<uint8_t> Buf);
+ void writeBuildId();
+
+private:
+ uint64_t Hash = 0xcbf29ce484222325; // FNV1 hash basis
+ uint8_t *HashBuf;
+};
+
// 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 <class ELFT> struct Out {
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Phdr Elf_Phdr;
+ static BuildIdSection<ELFT> *BuildId;
static DynamicSection<ELFT> *Dynamic;
static EhFrameHeader<ELFT> *EhFrameHdr;
static GnuHashTableSection<ELFT> *GnuHashTab;
static OutputSectionBase<ELFT> *ProgramHeaders;
};
+template <class ELFT> BuildIdSection<ELFT> *Out<ELFT>::BuildId;
template <class ELFT> DynamicSection<ELFT> *Out<ELFT>::Dynamic;
template <class ELFT> EhFrameHeader<ELFT> *Out<ELFT>::EhFrameHdr;
template <class ELFT> GnuHashTableSection<ELFT> *Out<ELFT>::GnuHashTab;
bool openFile();
void writeHeader();
void writeSections();
+ void writeBuildId();
bool isDiscarded(InputSectionBase<ELFT> *IS) const;
StringRef getOutputSectionName(InputSectionBase<ELFT> *S) const;
bool needsInterpSection() const {
ProgramHeaders.updateAlign(sizeof(uintX_t));
// Instantiate optional output sections if they are needed.
+ std::unique_ptr<BuildIdSection<ELFT>> BuildId;
std::unique_ptr<GnuHashTableSection<ELFT>> GnuHashTab;
std::unique_ptr<GotPltSection<ELFT>> GotPlt;
std::unique_ptr<HashTableSection<ELFT>> HashTab;
std::unique_ptr<SymbolTableSection<ELFT>> SymTabSec;
std::unique_ptr<OutputSection<ELFT>> MipsRldMap;
+ if (Config->BuildId)
+ BuildId.reset(new BuildIdSection<ELFT>);
if (Config->GnuHash)
GnuHashTab.reset(new GnuHashTableSection<ELFT>);
if (Config->SysvHash)
MipsRldMap->updateAlign(sizeof(uintX_t));
}
+ Out<ELFT>::BuildId = BuildId.get();
Out<ELFT>::DynStrTab = &DynStrTab;
Out<ELFT>::DynSymTab = &DynSymTab;
Out<ELFT>::Dynamic = &Dynamic;
return;
writeHeader();
writeSections();
+ writeBuildId();
if (HasError)
return;
check(Buffer->commit());
// This order is not the same as the final output order
// because we sort the sections using their attributes below.
+ Add(Out<ELFT>::BuildId);
Add(Out<ELFT>::SymTab);
Add(Out<ELFT>::ShStrTab);
Add(Out<ELFT>::StrTab);
Sec->writeTo(Buf + Sec->getFileOff());
}
+template <class ELFT> void Writer<ELFT>::writeBuildId() {
+ BuildIdSection<ELFT> *S = Out<ELFT>::BuildId;
+ if (!S)
+ return;
+
+ // Compute a hash 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<ELFT> *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 hash value field in the .note.gnu.build-id section.
+ S->writeBuildId();
+}
+
template void elf::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab);
template void elf::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab);
template void elf::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab);
--- /dev/null
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld --build-id %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=BUILDID %s
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=NO-BUILDID %s
+
+.globl _start;
+_start:
+ nop
+
+# BUILDID: Contents of section .note.gnu.build-id:
+# BUILDID-NEXT: 04000000 08000000 03000000 474e5500 ............GNU.
+
+# NO-BUILDID-NOT: Contents of section .note.gnu.build-id: