summaryrefslogtreecommitdiff
path: root/lld/COFF
diff options
context:
space:
mode:
authorQfrost <root@qfrost.com>2023-01-02 17:20:15 +0800
committerQfrost <root@qfrost.com>2023-01-02 17:20:15 +0800
commit3f55853edf93e1bb2e3c9b38fedfb7b8837464dc (patch)
tree2e7a3f31e8ae7f47207dabd8ca7e16acf4779a2a /lld/COFF
parent70423eedecea4015c1c0f2ca7df700d9063205ca (diff)
downloadllvm-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.h1
-rw-r--r--lld/COFF/Driver.cpp7
-rw-r--r--lld/COFF/Options.td2
-rw-r--r--lld/COFF/Writer.cpp40
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;