Index: lld/trunk/COFF/DriverUtils.cpp =================================================================== --- lld/trunk/COFF/DriverUtils.cpp +++ lld/trunk/COFF/DriverUtils.cpp @@ -718,7 +718,8 @@ } Expected> E = - llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser); + llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser, + Config->Timestamp); if (!E) fatal("failed to write .res to COFF: " + toString(E.takeError())); Index: llvm/trunk/include/llvm/Object/WindowsResource.h =================================================================== --- llvm/trunk/include/llvm/Object/WindowsResource.h +++ llvm/trunk/include/llvm/Object/WindowsResource.h @@ -232,7 +232,8 @@ Expected> writeWindowsResourceCOFF(llvm::COFF::MachineTypes MachineType, - const WindowsResourceParser &Parser); + const WindowsResourceParser &Parser, + uint32_t TimeDateStamp); void printResourceTypeName(uint16_t TypeID, raw_ostream &OS); } // namespace object Index: llvm/trunk/lib/Object/WindowsResource.cpp =================================================================== --- llvm/trunk/lib/Object/WindowsResource.cpp +++ llvm/trunk/lib/Object/WindowsResource.cpp @@ -400,13 +400,13 @@ public: WindowsResourceCOFFWriter(COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, Error &E); - std::unique_ptr write(); + std::unique_ptr write(uint32_t TimeDateStamp); private: void performFileLayout(); void performSectionOneLayout(); void performSectionTwoLayout(); - void writeCOFFHeader(); + void writeCOFFHeader(uint32_t TimeDateStamp); void writeFirstSectionHeader(); void writeSecondSectionHeader(); void writeFirstSection(); @@ -499,17 +499,11 @@ FileSize = alignTo(FileSize, SECTION_ALIGNMENT); } -static std::time_t getTime() { - std::time_t Now = time(nullptr); - if (Now < 0 || !isUInt<32>(Now)) - return UINT32_MAX; - return Now; -} - -std::unique_ptr WindowsResourceCOFFWriter::write() { +std::unique_ptr +WindowsResourceCOFFWriter::write(uint32_t TimeDateStamp) { BufferStart = OutputBuffer->getBufferStart(); - writeCOFFHeader(); + writeCOFFHeader(TimeDateStamp); writeFirstSectionHeader(); writeSecondSectionHeader(); writeFirstSection(); @@ -520,16 +514,17 @@ return std::move(OutputBuffer); } -void WindowsResourceCOFFWriter::writeCOFFHeader() { +void WindowsResourceCOFFWriter::writeCOFFHeader(uint32_t TimeDateStamp) { // Write the COFF header. auto *Header = reinterpret_cast(BufferStart); Header->Machine = MachineType; Header->NumberOfSections = 2; - Header->TimeDateStamp = getTime(); + Header->TimeDateStamp = TimeDateStamp; Header->PointerToSymbolTable = SymbolTableOffset; // One symbol for every resource plus 2 for each section and @feat.00 Header->NumberOfSymbols = Data.size() + 5; Header->SizeOfOptionalHeader = 0; + // cvtres.exe sets 32BIT_MACHINE even for 64-bit machine types. Match it. Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE; } @@ -794,12 +789,13 @@ Expected> writeWindowsResourceCOFF(COFF::MachineTypes MachineType, - const WindowsResourceParser &Parser) { + const WindowsResourceParser &Parser, + uint32_t TimeDateStamp) { Error E = Error::success(); WindowsResourceCOFFWriter Writer(MachineType, Parser, E); if (E) return std::move(E); - return Writer.write(); + return Writer.write(TimeDateStamp); } } // namespace object Index: llvm/trunk/test/tools/llvm-cvtres/help.test =================================================================== --- llvm/trunk/test/tools/llvm-cvtres/help.test +++ llvm/trunk/test/tools/llvm-cvtres/help.test @@ -10,4 +10,5 @@ ; HELP_TEST-DAG: /NOLOGO ; HELP_TEST-NEXT: /OUT:filename ; HELP_TEST-NEXT: /READONLY +; HELP_TEST-NEXT: /TIMESTAMP: Timestamp for coff header, defaults to current time ; HELP_TEST-NEXT: /VERBOSE Index: llvm/trunk/test/tools/llvm-cvtres/timestamp.test =================================================================== --- llvm/trunk/test/tools/llvm-cvtres/timestamp.test +++ llvm/trunk/test/tools/llvm-cvtres/timestamp.test @@ -0,0 +1,10 @@ +RUN: llvm-cvtres /timestamp:0x12345678 /out:%t %p/Inputs/test_resource.res +RUN: llvm-readobj -h %t | FileCheck %s --check-prefix=1TO8 + +1TO8: TimeDateStamp: 1979-09-05 22:51:36 (0x12345678) + + +RUN: not llvm-cvtres /timestamp:0x123456789 /out:%t \ +RUN: %p/Inputs/test_resource.res 2>&1 | FileCheck %s --check-prefix=ERR + +ERR: invalid timestamp: 0x123456789. Expected 32-bit integer Index: llvm/trunk/tools/llvm-cvtres/Opts.td =================================================================== --- llvm/trunk/tools/llvm-cvtres/Opts.td +++ llvm/trunk/tools/llvm-cvtres/Opts.td @@ -12,3 +12,8 @@ def HELP : Flag<["/", "-"], "HELP">; def H : Flag<["/", "-"], "H">, Alias; def HELP_Q : Flag<["/?", "-?"], "">, Alias; + +// Extensions. + +def TIMESTAMP : Joined<["/", "-"], "TIMESTAMP:">, + HelpText<"Timestamp for coff header, defaults to current time">; Index: llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp =================================================================== --- llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp +++ llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp @@ -88,6 +88,13 @@ [&](const ErrorInfoBase &EI) { reportError(EI.message()); }); } +static uint32_t getTime() { + std::time_t Now = time(nullptr); + if (Now < 0 || !isUInt<32>(Now)) + return UINT32_MAX; + return static_cast(Now); +} + template T error(Expected EC) { if (!EC) error(EC.takeError()); @@ -142,6 +149,16 @@ sys::path::replace_extension(OutputFile, ".obj"); } + uint32_t DateTimeStamp; + if (llvm::opt::Arg *Arg = InputArgs.getLastArg(OPT_TIMESTAMP)) { + StringRef Value(Arg->getValue()); + if (Value.getAsInteger(0, DateTimeStamp)) + reportError(Twine("invalid timestamp: ") + Value + + ". Expected 32-bit integer\n"); + } else { + DateTimeStamp = getTime(); + } + if (Verbose) { outs() << "Machine: "; switch (MachineType) { @@ -194,7 +211,8 @@ } std::unique_ptr OutputBuffer = - error(llvm::object::writeWindowsResourceCOFF(MachineType, Parser)); + error(llvm::object::writeWindowsResourceCOFF(MachineType, Parser, + DateTimeStamp)); auto FileOrErr = FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize()); if (!FileOrErr)