diff options
author | Qfrost <root@qfrost.com> | 2023-01-02 17:20:15 +0800 |
---|---|---|
committer | Qfrost <root@qfrost.com> | 2023-01-02 17:20:15 +0800 |
commit | 3f55853edf93e1bb2e3c9b38fedfb7b8837464dc (patch) | |
tree | 2e7a3f31e8ae7f47207dabd8ca7e16acf4779a2a /lld/COFF | |
parent | 70423eedecea4015c1c0f2ca7df700d9063205ca (diff) | |
download | llvm-3f55853edf93e1bb2e3c9b38fedfb7b8837464dc.tar.gz |
[LLD][Windows]Feature "checksum" for Windows PE
Differential Revision: https://reviews.llvm.org/D139184
Diffstat (limited to 'lld/COFF')
-rw-r--r-- | lld/COFF/Config.h | 1 | ||||
-rw-r--r-- | lld/COFF/Driver.cpp | 7 | ||||
-rw-r--r-- | lld/COFF/Options.td | 2 | ||||
-rw-r--r-- | lld/COFF/Writer.cpp | 40 |
4 files changed, 50 insertions, 0 deletions
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index b49b21e77351..c7f10f253b8a 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -289,6 +289,7 @@ struct Configuration { bool autoImport = false; bool pseudoRelocs = false; bool stdcallFixup = false; + bool writeCheckSum = false; }; extern std::unique_ptr<Configuration> config; diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 2c2b0dbad822..8c73e25d5630 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -415,6 +415,9 @@ void LinkerDriver::parseDirectives(InputFile *file) { case OPT_nodefaultlib: config->noDefaultLibs.insert(doFindLib(arg->getValue()).lower()); break; + case OPT_release: + config->writeCheckSum = true; + break; case OPT_section: parseSection(arg->getValue()); break; @@ -2021,6 +2024,10 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) { if (errorCount()) return; + // Handle /RELEASE + if (args.hasArg(OPT_release)) + config->writeCheckSum = true; + // Handle /safeseh, x86 only, on by default, except for mingw. if (config->machine == I386) { config->safeSEH = args.hasFlag(OPT_safeseh, OPT_safeseh_no, !config->mingw); diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td index fb4c65ef074b..df527bb48ae7 100644 --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -161,6 +161,8 @@ def swaprun_net : F<"swaprun:net">, Alias<swaprun>, AliasArgs<["net"]>, def verbose : F<"verbose">; def wholearchive_flag : F<"wholearchive">, HelpText<"Include all object files from all libraries">; +def release : F<"release">, + HelpText<"Set the Checksum in the header of an PE file">; def force : F<"force">, HelpText<"Allow undefined and multiply defined symbols">; diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 9875eee45eb9..ccadc26d27e8 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -229,6 +229,7 @@ private: void setSectionPermissions(); void writeSections(); void writeBuildId(); + void writePEChecksum(); void sortSections(); void sortExceptionTable(); void sortCRTSectionChunks(std::vector<Chunk *> &chunks); @@ -598,6 +599,43 @@ void Writer::finalizeAddresses() { } } +void Writer::writePEChecksum() { + if (!config->writeCheckSum) { + return; + } + + // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#checksum + uint32_t *buf = (uint32_t *)buffer->getBufferStart(); + uint32_t size = (uint32_t)(buffer->getBufferSize()); + + coff_file_header *coffHeader = + (coff_file_header *)((uint8_t *)buf + dosStubSize + sizeof(PEMagic)); + pe32_header *peHeader = + (pe32_header *)((uint8_t *)coffHeader + sizeof(coff_file_header)); + + uint64_t sum = 0; + uint32_t count = size; + ulittle16_t *addr = (ulittle16_t *)buf; + + // The PE checksum algorithm, implemented as suggested in RFC1071 + while (count > 1) { + sum += *addr++; + count -= 2; + } + + // Add left-over byte, if any + if (count > 0) + sum += *(unsigned char *)addr; + + // Fold 32-bit sum to 16 bits + while (sum >> 16) { + sum = (sum & 0xffff) + (sum >> 16); + } + + sum += size; + peHeader->CheckSum = sum; +} + // The main function of the writer. void Writer::run() { ScopedTimer t1(ctx.codeLayoutTimer); @@ -646,6 +684,8 @@ void Writer::run() { writeLLDMapFile(ctx); writeMapFile(ctx); + writePEChecksum(); + if (errorCount()) return; |