ELF: Implement --build-id.
This patch implements --build-id. After the linker creates an output file
in the memory buffer, it computes the FNV1 hash of the resulting file
and set the hash to the .note section as a build-id.
GNU ld and gold have the same feature, but their default choice of the
hash function is different. Their default is SHA1.
We made a deliberate choice to not use a secure hash function for the
sake of performance. Computing a secure hash is slow -- for example,
MD5 throughput is usually 400 MB/s or so. SHA1 is slower than that.
As a result, if you pass --build-id to gold, then the linker becomes about
10% slower than that without the option. We observed a similar degradation
in an experimental implementation of build-id for LLD. On the other hand,
we observed only 1-2% performance degradation with the FNV hash.
Since build-id is not for digital certificate or anything, we think that
a very small probability of collision is acceptable.
We considered using other signals such as using input file timestamps as
inputs to a secure hash function. But such signals would have an issue
with build reproducibility (if you build a binary from the same source
tree using the same toolchain, the build id should become the same.)
GNU linkers accepts --build-id=<style> option where style is one of
"MD5", "SHA1", or an arbitrary hex string. That option is out of scope
of this patch.
http://reviews.llvm.org/D18091
llvm-svn: 263292
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index a3a331f..5bde535 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -1530,6 +1530,36 @@
}
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;
@@ -1632,5 +1662,10 @@
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>;
}
}