Index: lld/trunk/COFF/Config.h =================================================================== --- lld/trunk/COFF/Config.h +++ lld/trunk/COFF/Config.h @@ -181,6 +181,7 @@ uint32_t MinorImageVersion = 0; uint32_t MajorOSVersion = 6; uint32_t MinorOSVersion = 0; + uint32_t Timestamp = 0; bool DynamicBase = true; bool AllowBind = true; bool NxCompat = true; @@ -194,6 +195,7 @@ bool WarnLocallyDefinedImported = true; bool Incremental = true; bool KillAt = false; + bool Repro = false; }; extern Configuration *Config; Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/COFF/Driver.cpp @@ -1033,6 +1033,23 @@ parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion, &Config->MinorOSVersion); + // Handle /timestamp + if (llvm::opt::Arg *Arg = Args.getLastArg(OPT_timestamp, OPT_repro)) { + if (Arg->getOption().getID() == OPT_repro) { + Config->Timestamp = 0; + Config->Repro = true; + } else { + Config->Repro = false; + StringRef Value(Arg->getValue()); + if (Value.getAsInteger(0, Config->Timestamp)) + fatal(Twine("invalid timestamp: ") + Value + + ". Expected 32-bit integer"); + } + } else { + Config->Repro = false; + Config->Timestamp = time(nullptr); + } + // Handle /alternatename for (auto *Arg : Args.filtered(OPT_alternatename)) parseAlternateName(Arg->getValue()); Index: lld/trunk/COFF/Options.td =================================================================== --- lld/trunk/COFF/Options.td +++ lld/trunk/COFF/Options.td @@ -58,6 +58,7 @@ def stack : P<"stack", "Size of the stack">; def stub : P<"stub", "Specify DOS stub file">; def subsystem : P<"subsystem", "Specify subsystem">; +def timestamp : P<"timestamp", "Specify the PE header timestamp">; def version : P<"version", "Specify a version number in the PE header">; def wholearchive_file : P<"wholearchive", "Include all object files from this archive">; @@ -89,6 +90,7 @@ def nodefaultlib_all : F<"nodefaultlib">; def noentry : F<"noentry">; def profile : F<"profile">; +def repro : F<"Brepro">, HelpText<"Use a hash of the executable as the PE header timestamp">; def swaprun_cd : F<"swaprun:cd">; def swaprun_net : F<"swaprun:net">; def verbose : F<"verbose">; Index: lld/trunk/COFF/Writer.cpp =================================================================== --- lld/trunk/COFF/Writer.cpp +++ lld/trunk/COFF/Writer.cpp @@ -1192,16 +1192,18 @@ reinterpret_cast(Buffer->getBufferStart()), Buffer->getBufferSize()); - uint32_t Hash = static_cast(xxHash64(OutputFileData)); + uint32_t Timestamp = Config->Timestamp; + if (Config->Repro) + Timestamp = static_cast(xxHash64(OutputFileData)); if (DebugDirectory) - DebugDirectory->setTimeDateStamp(Hash); + DebugDirectory->setTimeDateStamp(Timestamp); uint8_t *Buf = Buffer->getBufferStart(); Buf += DOSStubSize + sizeof(PEMagic); object::coff_file_header *CoffHeader = reinterpret_cast(Buf); - CoffHeader->TimeDateStamp = Hash; + CoffHeader->TimeDateStamp = Timestamp; } // Sort .pdata section contents according to PE/COFF spec 5.5. Index: lld/trunk/test/COFF/timestamp.test =================================================================== --- lld/trunk/test/COFF/timestamp.test +++ lld/trunk/test/COFF/timestamp.test @@ -0,0 +1,18 @@ +rm %t.*.exe +RUN: yaml2obj %p/Inputs/generic.yaml > %t.obj +RUN: lld-link %t.obj /debug /Brepro /entry:main /nodefaultlib /out:%t.1.exe +RUN: lld-link %t.obj /debug /Brepro /entry:main /nodefaultlib /out:%t.2.exe +RUN: lld-link %t.obj /debug /timestamp:0 /entry:main /nodefaultlib /out:%t.3.exe +RUN: llvm-readobj -file-headers -coff-debug-directory %t.1.exe | FileCheck %s --check-prefix=HASH +RUN: llvm-readobj -file-headers -coff-debug-directory %t.2.exe | FileCheck %s --check-prefix=HASH +RUN: llvm-readobj -file-headers -coff-debug-directory %t.3.exe | FileCheck %s --check-prefix=ZERO + +HASH: ImageFileHeader { +HASH: TimeDateStamp: [[STAMP:.*]] +HASH: DebugDirectory [ +HASH: TimeDateStamp: [[STAMP]] + +ZERO: ImageFileHeader { +ZERO: TimeDateStamp: 1970-01-01 00:00:00 (0x0) +ZERO: DebugDirectory [ +ZERO: TimeDateStamp: 1970-01-01 00:00:00 (0x0)