From: Zachary Turner Date: Thu, 8 Mar 2018 19:33:47 +0000 (+0000) Subject: Resubmit "Write a hash of the executable into the PE timestamp fields." X-Git-Tag: llvmorg-7.0.0-rc1~11077 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b575f46b6d2a1aeb7fdbbebd2654fa24165afae9;p=platform%2Fupstream%2Fllvm.git Resubmit "Write a hash of the executable into the PE timestamp fields." This fixes the broken tests that were causing failures. The tests before were verifying that the time stamp was 0, but now that we are actually writing a timestamp, I just removed the match against the timestamp value. llvm-svn: 327049 --- diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 3b026e2..b3a33ce 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -28,6 +28,7 @@ #include "llvm/Support/Parallel.h" #include "llvm/Support/Path.h" #include "llvm/Support/RandomNumberGenerator.h" +#include "llvm/Support/xxhash.h" #include #include #include @@ -103,11 +104,18 @@ public: uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA()); D->PointerToRawData = Offs; + TimeDateStamps.push_back(&D->TimeDateStamp); ++D; } } + void setTimeDateStamp(uint32_t TimeDateStamp) { + for (support::ulittle32_t *TDS : TimeDateStamps) + *TDS = TimeDateStamp; + } + private: + mutable std::vector TimeDateStamps; const std::vector &Records; }; @@ -189,7 +197,7 @@ private: RVATableChunk *GuardFidsTable = nullptr; RVATableChunk *SEHTable = nullptr; - Chunk *DebugDirectory = nullptr; + DebugDirectoryChunk *DebugDirectory = nullptr; std::vector DebugRecords; CVDebugRecordChunk *BuildId = nullptr; Optional PreviousBuildId; @@ -1070,22 +1078,50 @@ void Writer::writeSections() { } void Writer::writeBuildId() { - // If we're not writing a build id (e.g. because /debug is not specified), - // then just return; - if (!Config->Debug) - return; + // There are two important parts to the build ID. + // 1) If building with debug info, the COFF debug directory contains a + // timestamp as well as a Guid and Age of the PDB. + // 2) In all cases, the PE COFF file header also contains a timestamp. + // For reproducibility, instead of a timestamp we want to use a hash of the + // binary, however when building with debug info the hash needs to take into + // account the debug info, since it's possible to add blank lines to a file + // which causes the debug info to change but not the generated code. + // + // To handle this, we first set the Guid and Age in the debug directory (but + // only if we're doing a debug build). Then, we hash the binary (thus causing + // the hash to change if only the debug info changes, since the Age will be + // different). Finally, we write that hash into the debug directory (if + // present) as well as the COFF file header (always). + if (Config->Debug) { + assert(BuildId && "BuildId is not set!"); + if (PreviousBuildId.hasValue()) { + *BuildId->BuildId = *PreviousBuildId; + BuildId->BuildId->PDB70.Age = BuildId->BuildId->PDB70.Age + 1; + } else { + BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70; + BuildId->BuildId->PDB70.Age = 1; + llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16); + } + } - assert(BuildId && "BuildId is not set!"); + // At this point the only fields in the COFF file which remain unset are the + // "timestamp" in the COFF file header, and the ones in the coff debug + // directory. Now we can hash the file and write that hash to the various + // timestamp fields in the file. + StringRef OutputFileData( + reinterpret_cast(Buffer->getBufferStart()), + Buffer->getBufferSize()); - if (PreviousBuildId.hasValue()) { - *BuildId->BuildId = *PreviousBuildId; - BuildId->BuildId->PDB70.Age = BuildId->BuildId->PDB70.Age + 1; - return; - } + uint32_t Hash = static_cast(xxHash64(OutputFileData)); + + if (DebugDirectory) + DebugDirectory->setTimeDateStamp(Hash); - BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70; - BuildId->BuildId->PDB70.Age = 1; - llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16); + uint8_t *Buf = Buffer->getBufferStart(); + Buf += DOSStubSize + sizeof(PEMagic); + object::coff_file_header *CoffHeader = + reinterpret_cast(Buf); + CoffHeader->TimeDateStamp = Hash; } // Sort .pdata section contents according to PE/COFF spec 5.5. diff --git a/lld/test/COFF/hello32.test b/lld/test/COFF/hello32.test index 3b489d7..9f3cadc 100644 --- a/lld/test/COFF/hello32.test +++ b/lld/test/COFF/hello32.test @@ -11,7 +11,7 @@ HEADER-NEXT: AddressSize: 32bit HEADER-NEXT: ImageFileHeader { HEADER-NEXT: Machine: IMAGE_FILE_MACHINE_I386 (0x14C) HEADER-NEXT: SectionCount: 4 -HEADER-NEXT: TimeDateStamp: 1970-01-01 00:00:00 (0x0) +HEADER-NEXT: TimeDateStamp: HEADER-NEXT: PointerToSymbolTable: 0x0 HEADER-NEXT: SymbolCount: 0 HEADER-NEXT: OptionalHeaderSize: 224 diff --git a/lld/test/COFF/largeaddressaware.test b/lld/test/COFF/largeaddressaware.test index d035e7c..76aadee 100644 --- a/lld/test/COFF/largeaddressaware.test +++ b/lld/test/COFF/largeaddressaware.test @@ -9,7 +9,7 @@ HEADER-NEXT: AddressSize: 32bit HEADER-NEXT: ImageFileHeader { HEADER-NEXT: Machine: IMAGE_FILE_MACHINE_I386 (0x14C) HEADER-NEXT: SectionCount: 4 -HEADER-NEXT: TimeDateStamp: 1970-01-01 00:00:00 (0x0) +HEADER-NEXT: TimeDateStamp: HEADER-NEXT: PointerToSymbolTable: 0x0 HEADER-NEXT: SymbolCount: 0 HEADER-NEXT: OptionalHeaderSize: 224 diff --git a/lld/test/COFF/rsds.test b/lld/test/COFF/rsds.test index 17659778..10c2c56 100644 --- a/lld/test/COFF/rsds.test +++ b/lld/test/COFF/rsds.test @@ -18,7 +18,7 @@ # CHECK: DebugDirectory [ # CHECK: DebugEntry { # CHECK: Characteristics: 0x0 -# CHECK: TimeDateStamp: 1970-01-01 00:00:00 (0x0) +# CHECK: TimeDateStamp: # CHECK: MajorVersion: 0x0 # CHECK: MinorVersion: 0x0 # CHECK: Type: CodeView (0x2) @@ -37,7 +37,7 @@ # CHECK: DebugDirectory [ # CHECK: DebugEntry { # CHECK: Characteristics: 0x0 -# CHECK: TimeDateStamp: 1970-01-01 00:00:00 (0x0) +# CHECK: TimeDateStamp: # CHECK: MajorVersion: 0x0 # CHECK: MinorVersion: 0x0 # CHECK: Type: CodeView (0x2)