Index: lld/COFF/Writer.cpp =================================================================== --- lld/COFF/Writer.cpp +++ 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 @@ -71,11 +72,18 @@ 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; }; @@ -157,7 +165,7 @@ RVATableChunk *GuardFidsTable = nullptr; RVATableChunk *SEHTable = nullptr; - Chunk *DebugDirectory = nullptr; + DebugDirectoryChunk *DebugDirectory = nullptr; std::vector DebugRecords; CVDebugRecordChunk *BuildId = nullptr; Optional PreviousBuildId; @@ -1032,16 +1040,38 @@ return; assert(BuildId && "BuildId is not set!"); + assert(DebugDirectory && "DebugDirectory is not set!"); + + // Set the time stamp to a hash of the executable file, but do this before + // actually setting the guid and age, since those introduce some + // non-determinism. This way at least the hash will be deterministic. + // Note that there are several time stamps that need to be set, and they + // should all match. + // * The first is in the COFF file header which occurs immediately after + // the DOS stub at the beginning of the file. + // * The second occur in the debug directories, one in each directory. The + // PE spec says this should be the time that the debug information was + // created, but in practice I cannot find a link.exe generated binary where + // the values aren't identical to the one in the COFF file header. + StringRef OutputFileData( + reinterpret_cast(Buffer->getBufferStart()), + Buffer->getBufferSize()); + uint32_t Hash = static_cast(xxHash64(OutputFileData)); + DebugDirectory->setTimeDateStamp(Hash); + uint8_t *Buf = Buffer->getBufferStart(); + Buf += DOSStubSize + sizeof(PEMagic); + object::coff_file_header *CoffHeader = + reinterpret_cast(Buf); + CoffHeader->TimeDateStamp = Hash; if (PreviousBuildId.hasValue()) { *BuildId->BuildId = *PreviousBuildId; BuildId->BuildId->PDB70.Age = BuildId->BuildId->PDB70.Age + 1; - return; + } else { + BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70; + BuildId->BuildId->PDB70.Age = 1; + llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16); } - - BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70; - BuildId->BuildId->PDB70.Age = 1; - llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16); } // Sort .pdata section contents according to PE/COFF spec 5.5.