[llvm] [llvm-objcopy][COFF] Update WinCFGuard section contents after stripping (PR #153322)
Evgenii Kudriashov via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 13 15:10:22 PDT 2025
https://github.com/e-kud updated https://github.com/llvm/llvm-project/pull/153322
>From b302bd9732d5bc62d9dd59bead180a5c30973a1c Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Tue, 12 Aug 2025 17:38:14 -0700
Subject: [PATCH 1/2] [objcopy][COFF] Update WinCFGuard section contents after
stripping
After deleting debug sections symbol indexes are shifted but WinCFGuard
sections encode these indices into section data that is completely
ignored. Update symbol indices as well.
---
llvm/lib/ObjCopy/COFF/COFFObject.cpp | 3 +
llvm/lib/ObjCopy/COFF/COFFObject.h | 1 +
llvm/lib/ObjCopy/COFF/COFFWriter.cpp | 60 +++++
llvm/lib/ObjCopy/COFF/COFFWriter.h | 1 +
.../COFF/strip-update-winguards.test | 237 ++++++++++++++++++
5 files changed, 302 insertions(+)
create mode 100644 llvm/test/tools/llvm-objcopy/COFF/strip-update-winguards.test
diff --git a/llvm/lib/ObjCopy/COFF/COFFObject.cpp b/llvm/lib/ObjCopy/COFF/COFFObject.cpp
index 5fa13391c908f..fcb1bbfe91332 100644
--- a/llvm/lib/ObjCopy/COFF/COFFObject.cpp
+++ b/llvm/lib/ObjCopy/COFF/COFFObject.cpp
@@ -16,8 +16,11 @@ namespace coff {
using namespace object;
void Object::addSymbols(ArrayRef<Symbol> NewSymbols) {
+ size_t RawIndex = 0;
for (Symbol S : NewSymbols) {
S.UniqueId = NextSymbolUniqueId++;
+ S.OriginalRawIndex = RawIndex;
+ RawIndex += 1 + S.Sym.NumberOfAuxSymbols;
Symbols.emplace_back(S);
}
updateSymbols();
diff --git a/llvm/lib/ObjCopy/COFF/COFFObject.h b/llvm/lib/ObjCopy/COFF/COFFObject.h
index cdd1f17fc6055..9f88d45962513 100644
--- a/llvm/lib/ObjCopy/COFF/COFFObject.h
+++ b/llvm/lib/ObjCopy/COFF/COFFObject.h
@@ -89,6 +89,7 @@ struct Symbol {
std::optional<size_t> WeakTargetSymbolId;
size_t UniqueId;
size_t RawIndex;
+ size_t OriginalRawIndex;
bool Referenced;
};
diff --git a/llvm/lib/ObjCopy/COFF/COFFWriter.cpp b/llvm/lib/ObjCopy/COFF/COFFWriter.cpp
index 350c4aec572c9..4e3aa8201f0dc 100644
--- a/llvm/lib/ObjCopy/COFF/COFFWriter.cpp
+++ b/llvm/lib/ObjCopy/COFF/COFFWriter.cpp
@@ -12,6 +12,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/Object/COFF.h"
+#include "llvm/Support/CRC.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstddef>
@@ -92,6 +93,63 @@ Error COFFWriter::finalizeSymbolContents() {
return Error::success();
}
+Error COFFWriter::finalizeCFGuardContents() {
+ DenseMap<size_t, size_t> SymIdMap;
+ bool NeedUpdate = false;
+ for (Symbol &Sym : Obj.getMutableSymbols()) {
+ NeedUpdate |= Sym.OriginalRawIndex == Sym.RawIndex;
+ SymIdMap[Sym.OriginalRawIndex] = Sym.RawIndex;
+ }
+
+ if (!NeedUpdate)
+ return Error::success();
+
+ for (auto &Sym : Obj.getMutableSymbols()) {
+ if (Sym.Name != ".gljmp$y" && Sym.Name != ".giats$y" &&
+ Sym.Name != ".gfids$y")
+ continue;
+
+ auto Sec = find_if(Obj.getMutableSections(),
+ [&Sym](Section &S) { return S.Name == Sym.Name; });
+
+ if (Sec == Obj.getMutableSections().end() ||
+ Sec->UniqueId != Sym.TargetSectionId)
+ return createStringError(object_error::invalid_symbol_index,
+ "symbol '%s' is missing its section",
+ Sym.Name.str().c_str());
+
+ if (Sym.Sym.NumberOfAuxSymbols != 1 ||
+ Sym.Sym.StorageClass != IMAGE_SYM_CLASS_STATIC)
+ return createStringError(object_error::invalid_symbol_index,
+ "symbol '%s' has unexpected section format",
+ Sym.Name.str().c_str());
+
+ ArrayRef<uint8_t> RawIds = Sec->getContents();
+ // Nothing to do and also CheckSum will be -1 instead of 0 if we recalculate
+ // it on empty input.
+ if (RawIds.size() == 0)
+ return Error::success();
+
+ // Create updated content
+ ArrayRef<uint32_t> Ids(reinterpret_cast<const uint32_t *>(RawIds.data()),
+ RawIds.size() / 4);
+ std::vector<uint32_t> NewIds;
+ for (auto Id : Ids)
+ NewIds.push_back(SymIdMap[Id]);
+ ArrayRef<uint8_t> NewRawIds(reinterpret_cast<uint8_t *>(NewIds.data()),
+ RawIds.size());
+ // Update check sum
+ JamCRC JC(/*Init=*/0);
+ JC.update(NewRawIds);
+ coff_aux_section_definition *SD =
+ reinterpret_cast<coff_aux_section_definition *>(Sym.AuxData[0].Opaque);
+ SD->CheckSum = JC.getCRC();
+ // Set new content
+ Sec->setOwnedContents(NewRawIds);
+ }
+ return Error::success();
+}
+
void COFFWriter::layoutSections() {
for (auto &S : Obj.getMutableSections()) {
if (S.Header.SizeOfRawData > 0)
@@ -183,6 +241,8 @@ Error COFFWriter::finalize(bool IsBigObj) {
return E;
if (Error E = finalizeSymbolContents())
return E;
+ if (Error E = finalizeCFGuardContents())
+ return E;
size_t SizeOfHeaders = 0;
FileAlignment = 1;
diff --git a/llvm/lib/ObjCopy/COFF/COFFWriter.h b/llvm/lib/ObjCopy/COFF/COFFWriter.h
index b7dca69e9a81a..557dbe4c01b9c 100644
--- a/llvm/lib/ObjCopy/COFF/COFFWriter.h
+++ b/llvm/lib/ObjCopy/COFF/COFFWriter.h
@@ -34,6 +34,7 @@ class COFFWriter {
template <class SymbolTy> std::pair<size_t, size_t> finalizeSymbolTable();
Error finalizeRelocTargets();
Error finalizeSymbolContents();
+ Error finalizeCFGuardContents();
void layoutSections();
Expected<size_t> finalizeStringTable();
diff --git a/llvm/test/tools/llvm-objcopy/COFF/strip-update-winguards.test b/llvm/test/tools/llvm-objcopy/COFF/strip-update-winguards.test
new file mode 100644
index 0000000000000..4dc1a821dbd6a
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/COFF/strip-update-winguards.test
@@ -0,0 +1,237 @@
+# RUN: yaml2obj %s -o %t.in.o
+
+# RUN: llvm-readobj -r -s -x '.gfids$y' -x '.giats$y' -x '.gljmp$y' %t.in.o | FileCheck %s --check-prefix=ORIG
+# RUN: llvm-objcopy --strip-debug %t.in.o %t.out.o
+# RUN: llvm-readobj -r -s -x '.gfids$y' -x '.giats$y' -x '.gljmp$y' %t.out.o | FileCheck %s --check-prefix=STRIP
+
+# ORIG: Relocations [
+# ORIG-NEXT: Section (1) .text {
+# ORIG-NEXT: 0x3 IMAGE_REL_AMD64_REL32 foo (14)
+# ORIG-NEXT: 0xA IMAGE_REL_AMD64_REL32 bar (15)
+# ORIG-NEXT: 0x11 IMAGE_REL_AMD64_REL32 baz (16)
+# ORIG-NEXT: 0x18 IMAGE_REL_AMD64_REL32 foobar (17)
+# ORIG-NEXT: }
+# ORIG-NEXT: ]
+# ORIG: Symbols [
+# ORIG: Name: .gfids$y
+# ORIG: Section: .gfids$y
+# ORIG: AuxSymbolCount: 1
+# ORIG: AuxSectionDef {
+# ORIG: Checksum: 0x459345AD
+# ORIG: }
+# ORIG: Name: .giats$y
+# ORIG: Section: .giats$y
+# ORIG: AuxSymbolCount: 1
+# ORIG: AuxSectionDef {
+# ORIG: Checksum: 0x31852256
+# ORIG: }
+# ORIG: Name: .gljmp$y
+# ORIG: Section: .gljmp$y
+# ORIG: AuxSymbolCount: 1
+# ORIG: AuxSectionDef {
+# ORIG: Checksum: 0xC608680B
+# ORIG: }
+# ORIG: ]
+# ORIG: Hex dump of section '.gfids$y':
+# ORIG-NEXT: 0x00000000 0e000000 10000000 ........
+# ORIG: Hex dump of section '.giats$y':
+# ORIG-NEXT: 0x00000000 0f000000 11000000 ........
+# ORIG: Hex dump of section '.gljmp$y':
+# ORIG-NEXT: 0x00000000 0e000000 0f000000 10000000 11000000 ................
+
+# STRIP: Relocations [
+# STRIP-NEXT: Section (1) .text {
+# STRIP-NEXT: 0x3 IMAGE_REL_AMD64_REL32 foo (12)
+# STRIP-NEXT: 0xA IMAGE_REL_AMD64_REL32 bar (13)
+# STRIP-NEXT: 0x11 IMAGE_REL_AMD64_REL32 baz (14)
+# STRIP-NEXT: 0x18 IMAGE_REL_AMD64_REL32 foobar (15)
+# STRIP-NEXT: }
+# STRIP-NEXT: ]
+# STRIP: Symbols [
+# STRIP: Name: .gfids$y
+# STRIP: Section: .gfids$y
+# STRIP: AuxSymbolCount: 1
+# STRIP: AuxSectionDef {
+# STRIP: Checksum: 0xB770627C
+# STRIP: }
+# STRIP: Name: .giats$y
+# STRIP: Section: .giats$y
+# STRIP: AuxSymbolCount: 1
+# STRIP: AuxSectionDef {
+# STRIP: Checksum: 0xC3660587
+# STRIP: }
+# STRIP: Name: .gljmp$y
+# STRIP: Section: .gljmp$y
+# STRIP: AuxSymbolCount: 1
+# STRIP: AuxSectionDef {
+# STRIP: Checksum: 0x7464D042
+# STRIP: }
+# STRIP: ]
+# STRIP: Hex dump of section '.gfids$y':
+# STRIP-NEXT: 0x00000000 0c000000 0e000000 ........
+# STRIP: Hex dump of section '.giats$y':
+# STRIP-NEXT: 0x00000000 0d000000 0f000000 ........
+# STRIP: Hex dump of section '.gljmp$y':
+# STRIP-NEXT: 0x00000000 0c000000 0d000000 0e000000 0f000000 ................
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 488D0500000000488D0D00000000488D0500000000488D0500000000
+ SizeOfRawData: 28
+ Relocations:
+ - VirtualAddress: 3
+ SymbolName: foo
+ Type: IMAGE_REL_AMD64_REL32
+ - VirtualAddress: 10
+ SymbolName: bar
+ Type: IMAGE_REL_AMD64_REL32
+ - VirtualAddress: 17
+ SymbolName: baz
+ Type: IMAGE_REL_AMD64_REL32
+ - VirtualAddress: 24
+ SymbolName: foobar
+ Type: IMAGE_REL_AMD64_REL32
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: ''
+ - Name: .bss
+ Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: ''
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 04000000F100000044656275672073656374696F6E20746F20626520737472697070656400
+ SizeOfRawData: 37
+ - Name: '.gfids$y'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '0E00000010000000'
+ SizeOfRawData: 8
+ - Name: '.giats$y'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 0F00000011000000
+ SizeOfRawData: 8
+ - Name: '.gljmp$y'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 0E0000000F0000001000000011000000
+ SizeOfRawData: 16
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 28
+ NumberOfRelocations: 4
+ NumberOfLinenumbers: 0
+ CheckSum: 3583480811
+ Number: 1
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 2
+ - Name: .bss
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 3
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 37
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 2941632545
+ Number: 4
+ - Name: '.gfids$y'
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 1167279533
+ Number: 5
+ - Name: '.giats$y'
+ Value: 0
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 830808662
+ Number: 6
+ - Name: '.gljmp$y'
+ Value: 0
+ SectionNumber: 7
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 16
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 3322439691
+ Number: 7
+ - Name: foo
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: bar
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: baz
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: foobar
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
>From 42350aab8066c231e612f0a54d91c2f563e2d225 Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Wed, 13 Aug 2025 15:02:02 -0700
Subject: [PATCH 2/2] ulittle32_t, skip for PE and continue instead of return
---
llvm/lib/ObjCopy/COFF/COFFWriter.cpp | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/ObjCopy/COFF/COFFWriter.cpp b/llvm/lib/ObjCopy/COFF/COFFWriter.cpp
index 4e3aa8201f0dc..e5f47ad1f2d5b 100644
--- a/llvm/lib/ObjCopy/COFF/COFFWriter.cpp
+++ b/llvm/lib/ObjCopy/COFF/COFFWriter.cpp
@@ -14,6 +14,7 @@
#include "llvm/Object/COFF.h"
#include "llvm/Support/CRC.h"
#include "llvm/Support/Errc.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstddef>
#include <cstdint>
@@ -94,9 +95,13 @@ Error COFFWriter::finalizeSymbolContents() {
}
Error COFFWriter::finalizeCFGuardContents() {
+ // CFGuards shouldn't be present in PE
+ if (Obj.IsPE)
+ return Error::success();
+
DenseMap<size_t, size_t> SymIdMap;
bool NeedUpdate = false;
- for (Symbol &Sym : Obj.getMutableSymbols()) {
+ for (const auto &Sym : Obj.getSymbols()) {
NeedUpdate |= Sym.OriginalRawIndex == Sym.RawIndex;
SymIdMap[Sym.OriginalRawIndex] = Sym.RawIndex;
}
@@ -128,14 +133,14 @@ Error COFFWriter::finalizeCFGuardContents() {
// Nothing to do and also CheckSum will be -1 instead of 0 if we recalculate
// it on empty input.
if (RawIds.size() == 0)
- return Error::success();
+ continue;
// Create updated content
- ArrayRef<uint32_t> Ids(reinterpret_cast<const uint32_t *>(RawIds.data()),
- RawIds.size() / 4);
- std::vector<uint32_t> NewIds;
+ ArrayRef<support::ulittle32_t> Ids(reinterpret_cast<const support::ulittle32_t *>(RawIds.data()),
+ RawIds.size() / 4);
+ std::vector<support::ulittle32_t> NewIds;
for (auto Id : Ids)
- NewIds.push_back(SymIdMap[Id]);
+ NewIds.push_back(support::ulittle32_t(SymIdMap[Id]));
ArrayRef<uint8_t> NewRawIds(reinterpret_cast<uint8_t *>(NewIds.data()),
RawIds.size());
// Update check sum
More information about the llvm-commits
mailing list