[lld] 184377d - [LLD] Implement /guard:[no]ehcont
via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 14 00:07:07 PDT 2021
Author: Pengfei Wang
Date: 2021-04-14T15:06:49+08:00
New Revision: 184377da5c7ce624adf09341360c6cf8f31ebe8f
URL: https://github.com/llvm/llvm-project/commit/184377da5c7ce624adf09341360c6cf8f31ebe8f
DIFF: https://github.com/llvm/llvm-project/commit/184377da5c7ce624adf09341360c6cf8f31ebe8f.diff
LOG: [LLD] Implement /guard:[no]ehcont
Reviewed By: rnk
Differential Revision: https://reviews.llvm.org/D99078
Added:
lld/test/COFF/guard-ehcont.s
Modified:
lld/COFF/Chunks.cpp
lld/COFF/Chunks.h
lld/COFF/Config.h
lld/COFF/Driver.cpp
lld/COFF/DriverUtils.cpp
lld/COFF/InputFiles.cpp
lld/COFF/InputFiles.h
lld/COFF/Writer.cpp
lld/test/COFF/gfids-corrupt.s
lld/test/COFF/gfids-fallback.s
lld/test/COFF/gfids-gc.s
lld/test/COFF/gfids-icf.s
lld/test/COFF/giats.s
lld/test/COFF/guard-longjmp.s
lld/test/COFF/guardcf-lto.ll
llvm/include/llvm/Object/COFF.h
llvm/tools/llvm-readobj/COFFDumper.cpp
Removed:
################################################################################
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 14d0a5ad716cc..083742d6f55aa 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -801,6 +801,25 @@ void RVATableChunk::writeTo(uint8_t *buf) const {
"RVA tables should be de-duplicated");
}
+void RVAFlagTableChunk::writeTo(uint8_t *buf) const {
+ struct RVAFlag {
+ ulittle32_t rva;
+ uint8_t flag;
+ };
+ RVAFlag *begin = reinterpret_cast<RVAFlag *>(buf);
+ size_t cnt = 0;
+ for (const ChunkAndOffset &co : syms) {
+ begin[cnt].rva = co.inputChunk->getRVA() + co.offset;
+ begin[cnt].flag = 0;
+ ++cnt;
+ }
+ auto lt = [](RVAFlag &a, RVAFlag &b) { return a.rva < b.rva; };
+ auto eq = [](RVAFlag &a, RVAFlag &b) { return a.rva == b.rva; };
+ std::sort(begin, begin + cnt, lt);
+ assert(std::unique(begin, begin + cnt, eq) == begin + cnt &&
+ "RVA tables should be de-duplicated");
+}
+
// MinGW specific, for the "automatic import of variables from DLLs" feature.
size_t PseudoRelocTableChunk::getSize() const {
if (relocs.empty())
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index e076d8e71109a..49ee8b2a86294 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -584,6 +584,17 @@ class RVATableChunk : public NonSectionChunk {
SymbolRVASet syms;
};
+// Table which contains symbol RVAs with flags. Used for /guard:ehcont.
+class RVAFlagTableChunk : public NonSectionChunk {
+public:
+ explicit RVAFlagTableChunk(SymbolRVASet s) : syms(std::move(s)) {}
+ size_t getSize() const override { return syms.size() * 5; }
+ void writeTo(uint8_t *buf) const override;
+
+private:
+ SymbolRVASet syms;
+};
+
// Windows-specific.
// This class represents a block in .reloc section.
// See the PE/COFF spec 5.6 for details.
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index bde7b5b473d98..71ba27e19f069 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -74,10 +74,12 @@ enum class DebugType {
Fixup = 0x4, /// Relocation Table
};
-enum class GuardCFLevel {
- Off,
- NoLongJmp, // Emit gfids but no longjmp tables
- Full, // Enable all protections.
+enum GuardCFLevel {
+ Off = 0x0,
+ CF = 0x1, /// Emit gfids tables
+ LongJmp = 0x2, /// Emit longjmp tables
+ EHCont = 0x4, /// Emit ehcont tables
+ All = 0x7 /// Enable all protections
};
enum class ICFLevel {
@@ -143,7 +145,7 @@ struct Configuration {
bool saveTemps = false;
// /guard:cf
- GuardCFLevel guardCF = GuardCFLevel::Off;
+ int guardCF = GuardCFLevel::Off;
// Used for SafeSEH.
bool safeSEH = false;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index cf96ecb731a2c..072af2bef1598 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2008,6 +2008,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
symtab->addAbsolute(mangle("__guard_longjmp_table"), 0);
// Needed for MSVC 2017 15.5 CRT.
symtab->addAbsolute(mangle("__enclave_config"), 0);
+ // Needed for MSVC 2019 16.8 CRT.
+ symtab->addAbsolute(mangle("__guard_eh_cont_count"), 0);
+ symtab->addAbsolute(mangle("__guard_eh_cont_table"), 0);
if (config->pseudoRelocs) {
symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0);
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index 4c791130771b1..0b01a126b1da8 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -102,9 +102,15 @@ void parseGuard(StringRef fullArg) {
if (arg.equals_lower("no"))
config->guardCF = GuardCFLevel::Off;
else if (arg.equals_lower("nolongjmp"))
- config->guardCF = GuardCFLevel::NoLongJmp;
- else if (arg.equals_lower("cf") || arg.equals_lower("longjmp"))
- config->guardCF = GuardCFLevel::Full;
+ config->guardCF &= ~GuardCFLevel::LongJmp;
+ else if (arg.equals_lower("noehcont"))
+ config->guardCF &= ~GuardCFLevel::EHCont;
+ else if (arg.equals_lower("cf"))
+ config->guardCF = GuardCFLevel::CF;
+ else if (arg.equals_lower("longjmp"))
+ config->guardCF |= GuardCFLevel::CF | GuardCFLevel::LongJmp;
+ else if (arg.equals_lower("ehcont"))
+ config->guardCF |= GuardCFLevel::CF | GuardCFLevel::EHCont;
else
fatal("invalid argument to /guard: " + arg);
}
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index 37f66131620e6..c7b75badbfe21 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -284,6 +284,8 @@ SectionChunk *ObjFile::readSection(uint32_t sectionNumber,
guardIATChunks.push_back(c);
else if (name == ".gljmp$y")
guardLJmpChunks.push_back(c);
+ else if (name == ".gehcont$y")
+ guardEHContChunks.push_back(c);
else if (name == ".sxdata")
sxDataChunks.push_back(c);
else if (config->tailMerge && sec->NumberOfRelocations == 0 &&
diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h
index 3fa6819157a91..644369f9ee984 100644
--- a/lld/COFF/InputFiles.h
+++ b/lld/COFF/InputFiles.h
@@ -146,6 +146,7 @@ class ObjFile : public InputFile {
ArrayRef<SectionChunk *> getGuardFidChunks() { return guardFidChunks; }
ArrayRef<SectionChunk *> getGuardIATChunks() { return guardIATChunks; }
ArrayRef<SectionChunk *> getGuardLJmpChunks() { return guardLJmpChunks; }
+ ArrayRef<SectionChunk *> getGuardEHContChunks() { return guardEHContChunks; }
ArrayRef<Symbol *> getSymbols() { return symbols; }
MutableArrayRef<Symbol *> getMutableSymbols() { return symbols; }
@@ -184,7 +185,7 @@ class ObjFile : public InputFile {
bool hasSafeSEH() { return feat00Flags & 0x1; }
// True if this file was compiled with /guard:cf.
- bool hasGuardCF() { return feat00Flags & 0x800; }
+ bool hasGuardCF() { return feat00Flags & 0x4800; }
// Pointer to the PDB module descriptor builder. Various debug info records
// will reference object files by "module index", which is here. Things like
@@ -287,11 +288,12 @@ class ObjFile : public InputFile {
std::vector<SectionChunk *> sxDataChunks;
// Chunks containing symbol table indices of address taken symbols, address
- // taken IAT entries, and longjmp targets. These are not linked into the
- // final binary when /guard:cf is set.
+ // taken IAT entries, longjmp and ehcont targets. These are not linked into
+ // the final binary when /guard:cf is set.
std::vector<SectionChunk *> guardFidChunks;
std::vector<SectionChunk *> guardIATChunks;
std::vector<SectionChunk *> guardLJmpChunks;
+ std::vector<SectionChunk *> guardEHContChunks;
// This vector contains a list of all symbols defined or referenced by this
// file. They are indexed such that you can get a Symbol by symbol
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 344e83f410149..09c456e648999 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -231,7 +231,7 @@ class Writer {
ArrayRef<SectionChunk *> symIdxChunks,
std::vector<Symbol *> &symbols);
void maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
- StringRef countSym);
+ StringRef countSym, bool hasFlag=false);
void setSectionPermissions();
void writeSections();
void writeBuildId();
@@ -1635,17 +1635,20 @@ void Writer::createGuardCFTables() {
SymbolRVASet giatsRVASet;
std::vector<Symbol *> giatsSymbols;
SymbolRVASet longJmpTargets;
+ SymbolRVASet ehContTargets;
for (ObjFile *file : ObjFile::instances) {
// If the object was compiled with /guard:cf, the address taken symbols
- // are in .gfids$y sections, and the longjmp targets are in .gljmp$y
- // sections. If the object was not compiled with /guard:cf, we assume there
- // were no setjmp targets, and that all code symbols with relocations are
- // possibly address-taken.
+ // are in .gfids$y sections, the longjmp targets are in .gljmp$y sections,
+ // and ehcont targets are in .gehcont$y sections. If the object was not
+ // compiled with /guard:cf, we assume there were no setjmp and ehcont
+ // targets, and that all code symbols with relocations are possibly
+ // address-taken.
if (file->hasGuardCF()) {
markSymbolsForRVATable(file, file->getGuardFidChunks(), addressTakenSyms);
markSymbolsForRVATable(file, file->getGuardIATChunks(), giatsRVASet);
getSymbolsFromSections(file, file->getGuardIATChunks(), giatsSymbols);
markSymbolsForRVATable(file, file->getGuardLJmpChunks(), longJmpTargets);
+ markSymbolsForRVATable(file, file->getGuardEHContChunks(), ehContTargets);
} else {
markSymbolsWithRelocations(file, addressTakenSyms);
}
@@ -1682,16 +1685,23 @@ void Writer::createGuardCFTables() {
"__guard_iat_count");
// Add the longjmp target table unless the user told us not to.
- if (config->guardCF == GuardCFLevel::Full)
+ if (config->guardCF & GuardCFLevel::LongJmp)
maybeAddRVATable(std::move(longJmpTargets), "__guard_longjmp_table",
"__guard_longjmp_count");
+ // Add the ehcont target table unless the user told us not to.
+ if (config->guardCF & GuardCFLevel::EHCont)
+ maybeAddRVATable(std::move(ehContTargets), "__guard_eh_cont_table",
+ "__guard_eh_cont_count", true);
+
// Set __guard_flags, which will be used in the load config to indicate that
// /guard:cf was enabled.
uint32_t guardFlags = uint32_t(coff_guard_flags::CFInstrumented) |
uint32_t(coff_guard_flags::HasFidTable);
- if (config->guardCF == GuardCFLevel::Full)
+ if (config->guardCF & GuardCFLevel::LongJmp)
guardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable);
+ if (config->guardCF & GuardCFLevel::EHCont)
+ guardFlags |= uint32_t(coff_guard_flags::HasEHContTable);
Symbol *flagSym = symtab->findUnderscore("__guard_flags");
cast<DefinedAbsolute>(flagSym)->setVA(guardFlags);
}
@@ -1753,17 +1763,21 @@ void Writer::markSymbolsForRVATable(ObjFile *file,
// tableChunk so that we can emit base relocations for it and resolve section
// relative relocations.
void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
- StringRef countSym) {
+ StringRef countSym, bool hasFlag) {
if (tableSymbols.empty())
return;
- RVATableChunk *tableChunk = make<RVATableChunk>(std::move(tableSymbols));
+ NonSectionChunk *tableChunk;
+ if (hasFlag)
+ tableChunk = make<RVAFlagTableChunk>(std::move(tableSymbols));
+ else
+ tableChunk = make<RVATableChunk>(std::move(tableSymbols));
rdataSec->addChunk(tableChunk);
Symbol *t = symtab->findUnderscore(tableSym);
Symbol *c = symtab->findUnderscore(countSym);
replaceSymbol<DefinedSynthetic>(t, t->getName(), tableChunk);
- cast<DefinedAbsolute>(c)->setVA(tableChunk->getSize() / 4);
+ cast<DefinedAbsolute>(c)->setVA(tableChunk->getSize() / (hasFlag ? 5 : 4));
}
// MinGW specific. Gather all relocations that are imported from a DLL even
diff --git a/lld/test/COFF/gfids-corrupt.s b/lld/test/COFF/gfids-corrupt.s
index a571f2fb67f0c..159f9c95a64fb 100644
--- a/lld/test/COFF/gfids-corrupt.s
+++ b/lld/test/COFF/gfids-corrupt.s
@@ -1,6 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
-# RUN: lld-link %t.obj -opt:noref -guard:nolongjmp -out:%t.exe -entry:main 2>&1 | FileCheck %s --check-prefix=ERRS
+# RUN: lld-link %t.obj -opt:noref -guard:cf -out:%t.exe -entry:main 2>&1 | FileCheck %s --check-prefix=ERRS
# RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s
# ERRS: warning: ignoring .gfids$y symbol table index section in object {{.*}}gfids-corrupt{{.*}}
diff --git a/lld/test/COFF/gfids-fallback.s b/lld/test/COFF/gfids-fallback.s
index be94e2efb38e8..4b23f62900455 100644
--- a/lld/test/COFF/gfids-fallback.s
+++ b/lld/test/COFF/gfids-fallback.s
@@ -1,7 +1,7 @@
# REQUIRES: x86
# RUN: grep -B99999 [S]PLITMARKER %s | llvm-mc -triple x86_64-windows-msvc -filetype=obj -o %t1.obj
# RUN: grep -A99999 [S]PLITMARKER %s | llvm-mc -triple x86_64-windows-msvc -filetype=obj -o %t2.obj
-# RUN: lld-link %t1.obj %t2.obj -guard:nolongjmp -out:%t.exe -entry:main -opt:noref
+# RUN: lld-link %t1.obj %t2.obj -guard:cf -out:%t.exe -entry:main -opt:noref
# RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s
# CHECK: ImageBase: 0x140000000
diff --git a/lld/test/COFF/gfids-gc.s b/lld/test/COFF/gfids-gc.s
index cf4b5fdae07ae..fb63c95a7d4d1 100644
--- a/lld/test/COFF/gfids-gc.s
+++ b/lld/test/COFF/gfids-gc.s
@@ -1,10 +1,10 @@
# REQUIRES: x86
# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
-# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:noref -entry:main
+# RUN: lld-link %t.obj -guard:cf -out:%t.exe -opt:noref -entry:main
# RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
-# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:noref -entry:main -debug:dwarf
+# RUN: lld-link %t.obj -guard:cf -out:%t.exe -opt:noref -entry:main -debug:dwarf
# RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
-# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:ref -entry:main
+# RUN: lld-link %t.obj -guard:cf -out:%t.exe -opt:ref -entry:main
# RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-GC
# This assembly is meant to mimic what CL emits for this kind of C code when
diff --git a/lld/test/COFF/gfids-icf.s b/lld/test/COFF/gfids-icf.s
index 7cf7ddac17fc0..afd0462bfb601 100644
--- a/lld/test/COFF/gfids-icf.s
+++ b/lld/test/COFF/gfids-icf.s
@@ -1,6 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
-# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:icf -entry:main
+# RUN: lld-link %t.obj -guard:cf -out:%t.exe -opt:icf -entry:main
# RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK
# This assembly is meant to mimic what CL emits for this kind of C code:
diff --git a/lld/test/COFF/giats.s b/lld/test/COFF/giats.s
index fe4e33b10308a..4a6147237737d 100644
--- a/lld/test/COFF/giats.s
+++ b/lld/test/COFF/giats.s
@@ -8,7 +8,7 @@
# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %basename_t.obj
# Check that the Guard address-taken IAT entry tables are propagated to the final executable.
-# RUN: lld-link %basename_t.obj -guard:cf -entry:main -out:%basename_t-nodelay.exe %basename_t-exp.lib
+# RUN: lld-link %basename_t.obj -guard:cf -guard:longjmp -entry:main -out:%basename_t-nodelay.exe %basename_t-exp.lib
# RUN: llvm-readobj --file-headers --coff-load-config %basename_t-nodelay.exe | FileCheck %s --check-prefix CHECK
# CHECK: ImageBase: 0x140000000
@@ -28,7 +28,7 @@
# Check that the additional load thunk symbol is added to the GFIDs table.
-# RUN: lld-link %basename_t.obj -guard:cf -entry:main -out:%basename_t-delay.exe %basename_t-exp.lib -alternatename:__delayLoadHelper2=main -delayload:%basename_t-exp.dll
+# RUN: lld-link %basename_t.obj -guard:cf -guard:longjmp -entry:main -out:%basename_t-delay.exe %basename_t-exp.lib -alternatename:__delayLoadHelper2=main -delayload:%basename_t-exp.dll
# RUN: llvm-readobj --file-headers --coff-load-config %basename_t-delay.exe | FileCheck %s --check-prefix DELAY-CHECK
# DELAY-CHECK: ImageBase: 0x140000000
diff --git a/lld/test/COFF/guard-ehcont.s b/lld/test/COFF/guard-ehcont.s
new file mode 100644
index 0000000000000..2177143d67ef6
--- /dev/null
+++ b/lld/test/COFF/guard-ehcont.s
@@ -0,0 +1,224 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -guard:cf -guard:ehcont -out:%t.exe -entry:main
+# RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s
+
+# CHECK: ImageBase: 0x140000000
+# CHECK: LoadConfig [
+# CHECK: SEHandlerTable: 0x0
+# CHECK: SEHandlerCount: 0
+# CHECK: GuardCFCheckFunction: 0x0
+# CHECK: GuardCFCheckDispatch: 0x0
+# CHECK: GuardCFFunctionTable: 0x14000{{.*}}
+# CHECK: GuardCFFunctionCount: 1
+# CHECK: GuardFlags: 0x400500
+# CHECK: GuardAddressTakenIatEntryTable: 0x0
+# CHECK: GuardAddressTakenIatEntryCount: 0
+# CHECK: GuardEHContinuationTable: 0x14000{{.*}}
+# CHECK: GuardEHContinuationCount: 1
+# CHECK: ]
+# CHECK: GuardEHContTable [
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: ]
+
+
+# This assembly is reduced from C code like:
+# int main()
+# {
+# try {
+# throw 3;
+# }
+# catch (int e) {
+# return e != 3;
+# }
+# return 2;
+# }
+
+# We need @feat.00 to have 0x4000 to indicate /guard:ehcont.
+ .def @feat.00;
+ .scl 3;
+ .type 0;
+ .endef
+ .globl @feat.00
+ at feat.00 = 0x4000
+ .def main; .scl 2; .type 32; .endef
+ .globl main # -- Begin function main
+ .p2align 4, 0x90
+main: # @main
+.Lfunc_begin0:
+.seh_proc main
+.intel_syntax
+ .seh_handler __CxxFrameHandler3, @unwind, @except
+# %bb.0: # %entry
+ push rbp
+ .seh_pushreg rbp
+ sub rsp, 64
+ .seh_stackalloc 64
+ lea rbp, [rsp + 64]
+ .seh_setframe rbp, 64
+ .seh_endprologue
+ mov qword ptr [rbp - 16], -2
+ mov dword ptr [rbp - 20], 0
+ mov dword ptr [rbp - 24], 3
+.Ltmp0:
+ lea rdx, [rip + _TI1H]
+ lea rcx, [rbp - 24]
+ call _CxxThrowException
+.Ltmp1:
+ jmp .LBB0_3
+.LBB0_2: # Block address taken
+ # %catchret.dest
+$ehgcr_0_2:
+ mov eax, dword ptr [rbp - 20]
+ add rsp, 64
+ pop rbp
+ ret
+.LBB0_3: # %unreachable
+ int3
+ .seh_handlerdata
+ .long ($cppxdata$main)@IMGREL
+ .text
+ .seh_endproc
+ .def "?catch$1@?0?main at 4HA";
+ .scl 3;
+ .type 32;
+ .endef
+ .p2align 4, 0x90
+"?catch$1@?0?main at 4HA":
+.seh_proc "?catch$1@?0?main at 4HA"
+ .seh_handler __CxxFrameHandler3, @unwind, @except
+.LBB0_1: # %catch
+ mov qword ptr [rsp + 16], rdx
+ push rbp
+ .seh_pushreg rbp
+ sub rsp, 32
+ .seh_stackalloc 32
+ lea rbp, [rdx + 64]
+ .seh_endprologue
+ mov eax, dword ptr [rbp - 4]
+ sub eax, 3
+ setne al
+ movzx eax, al
+ mov dword ptr [rbp - 20], eax
+ lea rax, [rip + .LBB0_2]
+ add rsp, 32
+ pop rbp
+ ret # CATCHRET
+ .def free; .scl 2; .type 32; .endef
+ .globl free
+free:
+ ret
+ .def __CxxFrameHandler3; .scl 2; .type 32; .endef
+ .globl __CxxFrameHandler3
+__CxxFrameHandler3:
+ ret
+ .def _CxxThrowException; .scl 2; .type 32; .endef
+ .globl _CxxThrowException
+_CxxThrowException:
+ ret
+.Lfunc_end0:
+ .seh_handlerdata
+ .long ($cppxdata$main)@IMGREL
+ .text
+ .seh_endproc
+ .section .xdata,"dr"
+ .p2align 2
+$cppxdata$main:
+ .long 429065506 # MagicNumber
+ .long 2 # MaxState
+ .long ($stateUnwindMap$main)@IMGREL # UnwindMap
+ .long 1 # NumTryBlocks
+ .long ($tryMap$main)@IMGREL # TryBlockMap
+ .long 4 # IPMapEntries
+ .long ($ip2state$main)@IMGREL # IPToStateXData
+ .long 48 # UnwindHelp
+ .long 0 # ESTypeList
+ .long 1 # EHFlags
+$stateUnwindMap$main:
+ .long -1 # ToState
+ .long 0 # Action
+ .long -1 # ToState
+ .long 0 # Action
+$tryMap$main:
+ .long 0 # TryLow
+ .long 0 # TryHigh
+ .long 1 # CatchHigh
+ .long 1 # NumCatches
+ .long ($handlerMap$0$main)@IMGREL # HandlerArray
+$handlerMap$0$main:
+ .long 0 # Adjectives
+ .long "??_R0H at 8"@IMGREL # Type
+ .long 60 # CatchObjOffset
+ .long "?catch$1@?0?main at 4HA"@IMGREL # Handler
+ .long 56 # ParentFrameOffset
+$ip2state$main:
+ .long .Lfunc_begin0 at IMGREL # IP
+ .long -1 # ToState
+ .long .Ltmp0 at IMGREL+1 # IP
+ .long 0 # ToState
+ .long .Ltmp1 at IMGREL+1 # IP
+ .long -1 # ToState
+ .long "?catch$1@?0?main at 4HA"@IMGREL # IP
+ .long 1 # ToState
+ .text
+ # -- End function
+ .section .data,"dw",discard,"??_R0H at 8"
+ .globl "??_R0H at 8" # @"??_R0H at 8"
+ .p2align 4
+"??_R0H at 8":
+ .quad 0
+ .quad 0
+ .asciz ".H"
+ .zero 5
+
+ .section .xdata,"dr",discard,"_CT??_R0H at 84"
+ .globl "_CT??_R0H at 84" # @"_CT??_R0H at 84"
+ .p2align 4
+"_CT??_R0H at 84":
+ .long 1 # 0x1
+ .long "??_R0H at 8"@IMGREL
+ .long 0 # 0x0
+ .long 4294967295 # 0xffffffff
+ .long 0 # 0x0
+ .long 4 # 0x4
+ .long 0 # 0x0
+
+ .section .xdata,"dr",discard,_CTA1H
+ .globl _CTA1H # @_CTA1H
+ .p2align 3
+_CTA1H:
+ .long 1 # 0x1
+ .long "_CT??_R0H at 84"@IMGREL
+
+ .section .xdata,"dr",discard,_TI1H
+ .globl _TI1H # @_TI1H
+ .p2align 3
+_TI1H:
+ .long 0 # 0x0
+ .long 0 # 0x0
+ .long 0 # 0x0
+ .long _CTA1H at IMGREL
+
+ .section .gehcont$y,"dr"
+ .symidx $ehgcr_0_2
+ .addrsig_sym _CxxThrowException
+ .addrsig_sym __CxxFrameHandler3
+ .addrsig_sym "??_R0H at 8"
+ .addrsig_sym __ImageBase
+ .section .rdata,"dr"
+.globl _load_config_used
+_load_config_used:
+ .long 312
+ .fill 124, 1, 0
+ .quad __guard_fids_table
+ .quad __guard_fids_count
+ .long __guard_flags
+ .fill 12, 1, 0
+ .quad __guard_iat_table
+ .quad __guard_iat_count
+ .quad __guard_longjmp_table
+ .quad __guard_longjmp_count
+ .fill 72, 1, 0
+ .quad __guard_eh_cont_table
+ .quad __guard_eh_cont_count
+ .fill 32, 1, 0
\ No newline at end of file
diff --git a/lld/test/COFF/guard-longjmp.s b/lld/test/COFF/guard-longjmp.s
index 51ca41420f691..dbef81970d2dd 100644
--- a/lld/test/COFF/guard-longjmp.s
+++ b/lld/test/COFF/guard-longjmp.s
@@ -1,6 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
-# RUN: lld-link %t.obj -guard:cf -out:%t.exe -entry:main
+# RUN: lld-link %t.obj -guard:cf -guard:longjmp -out:%t.exe -entry:main
# RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s
# CHECK: ImageBase: 0x140000000
@@ -100,5 +100,5 @@ _load_config_used:
.quad __guard_iat_table
.quad __guard_iat_count
.quad __guard_longjmp_table
- .quad __guard_fids_count
+ .quad __guard_longjmp_count
.fill 84, 1, 0
diff --git a/lld/test/COFF/guardcf-lto.ll b/lld/test/COFF/guardcf-lto.ll
index 7811f442ef391..5917044f13cc2 100644
--- a/lld/test/COFF/guardcf-lto.ll
+++ b/lld/test/COFF/guardcf-lto.ll
@@ -8,7 +8,7 @@
; RUN: llvm-mc -triple x86_64-windows-msvc -filetype=obj %S/Inputs/loadconfig-cfg-x64.s -o %t.ldcfg.obj
; RUN: llvm-as %s -o %t.bc
-; RUN: lld-link -entry:main -guard:cf -dll %t.bc %t.lib %t.ldcfg.obj -out:%t2.dll
+; RUN: lld-link -entry:main -guard:cf -guard:longjmp -dll %t.bc %t.lib %t.ldcfg.obj -out:%t2.dll
; RUN: llvm-readobj --coff-load-config %t2.dll | FileCheck %s
; There must be *two* entries in the table: DLL entry point, and my_handler.
diff --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h
index e7cf1b5495c66..2e8ff989580a1 100644
--- a/llvm/include/llvm/Object/COFF.h
+++ b/llvm/include/llvm/Object/COFF.h
@@ -604,6 +604,7 @@ enum class coff_guard_flags : uint32_t {
ProtectDelayLoadIAT = 0x00001000,
DelayLoadIATSection = 0x00002000, // Delay load in separate section
HasLongJmpTable = 0x00010000,
+ HasEHContTable = 0x00400000,
FidTableHasFlags = 0x10000000, // Indicates that fid tables are 5 bytes
};
@@ -661,6 +662,17 @@ struct coff_load_configuration32 {
support::ulittle16_t Reserved2;
support::ulittle32_t GuardRFVerifyStackPointerFunctionPointer;
support::ulittle32_t HotPatchTableOffset;
+
+ // Added in MSVC 2019
+ support::ulittle32_t Reserved3;
+ support::ulittle32_t EnclaveConfigurationPointer;
+ support::ulittle32_t VolatileMetadataPointer;
+ support::ulittle32_t GuardEHContinuationTable;
+ support::ulittle32_t GuardEHContinuationCount;
+ support::ulittle32_t GuardXFGCheckFunctionPointer;
+ support::ulittle32_t GuardXFGDispatchFunctionPointer;
+ support::ulittle32_t GuardXFGTableDispatchFunctionPointer;
+ support::ulittle32_t CastGuardOsDeterminedFailureMode;
};
/// 64-bit load config (IMAGE_LOAD_CONFIG_DIRECTORY64)
@@ -708,6 +720,17 @@ struct coff_load_configuration64 {
support::ulittle16_t Reserved2;
support::ulittle64_t GuardRFVerifyStackPointerFunctionPointer;
support::ulittle32_t HotPatchTableOffset;
+
+ // Added in MSVC 2019
+ support::ulittle32_t Reserved3;
+ support::ulittle64_t EnclaveConfigurationPointer;
+ support::ulittle64_t VolatileMetadataPointer;
+ support::ulittle64_t GuardEHContinuationTable;
+ support::ulittle64_t GuardEHContinuationCount;
+ support::ulittle64_t GuardXFGCheckFunctionPointer;
+ support::ulittle64_t GuardXFGDispatchFunctionPointer;
+ support::ulittle64_t GuardXFGTableDispatchFunctionPointer;
+ support::ulittle64_t CastGuardOsDeterminedFailureMode;
};
struct coff_runtime_function_x64 {
diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index 2a77ebe34bc6e..4647b24f8ba4c 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -71,6 +71,8 @@ struct LoadConfigTables {
uint64_t GuardIatTableCount = 0;
uint64_t GuardLJmpTableVA = 0;
uint64_t GuardLJmpTableCount = 0;
+ uint64_t GuardEHContTableVA = 0;
+ uint64_t GuardEHContTableCount = 0;
};
class COFFDumper : public ObjDumper {
@@ -793,19 +795,19 @@ void COFFDumper::printCOFFLoadConfig() {
printRVATable(Tables.SEHTableVA, Tables.SEHTableCount, 4);
}
+ auto PrintGuardFlags = [](raw_ostream &OS, const uint8_t *Entry) {
+ uint8_t Flags = *reinterpret_cast<const uint8_t *>(Entry + 4);
+ if (Flags)
+ OS << " flags " << utohexstr(Flags);
+ };
+
if (Tables.GuardFidTableVA) {
ListScope LS(W, "GuardFidTable");
- if (Tables.GuardFlags & uint32_t(coff_guard_flags::FidTableHasFlags)) {
- auto PrintGuardFlags = [](raw_ostream &OS, const uint8_t *Entry) {
- uint8_t Flags = *reinterpret_cast<const uint8_t *>(Entry + 4);
- if (Flags)
- OS << " flags " << utohexstr(Flags);
- };
+ if (Tables.GuardFlags & uint32_t(coff_guard_flags::FidTableHasFlags))
printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 5,
PrintGuardFlags);
- } else {
+ else
printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 4);
- }
}
if (Tables.GuardIatTableVA) {
@@ -817,6 +819,12 @@ void COFFDumper::printCOFFLoadConfig() {
ListScope LS(W, "GuardLJmpTable");
printRVATable(Tables.GuardLJmpTableVA, Tables.GuardLJmpTableCount, 4);
}
+
+ if (Tables.GuardEHContTableVA) {
+ ListScope LS(W, "GuardEHContTable");
+ printRVATable(Tables.GuardEHContTableVA, Tables.GuardEHContTableCount, 5,
+ PrintGuardFlags);
+ }
}
template <typename T>
@@ -875,8 +883,8 @@ void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) {
Tables.GuardFidTableCount = Conf->GuardCFFunctionCount;
Tables.GuardFlags = Conf->GuardFlags;
- // Print the rest. (2017)
- if (Conf->Size < sizeof(T))
+ // Print everything before Reserved3. (2017)
+ if (Conf->Size < offsetof(T, Reserved3))
return;
W.printHex("GuardAddressTakenIatEntryTable",
Conf->GuardAddressTakenIatEntryTable);
@@ -902,6 +910,17 @@ void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) {
Tables.GuardLJmpTableVA = Conf->GuardLongJumpTargetTable;
Tables.GuardLJmpTableCount = Conf->GuardLongJumpTargetCount;
+
+ // Print the rest. (2019)
+ if (Conf->Size < sizeof(T))
+ return;
+ W.printHex("EnclaveConfigurationPointer", Conf->EnclaveConfigurationPointer);
+ W.printHex("VolatileMetadataPointer", Conf->VolatileMetadataPointer);
+ W.printHex("GuardEHContinuationTable", Conf->GuardEHContinuationTable);
+ W.printNumber("GuardEHContinuationCount", Conf->GuardEHContinuationCount);
+
+ Tables.GuardEHContTableVA = Conf->GuardEHContinuationTable;
+ Tables.GuardEHContTableCount = Conf->GuardEHContinuationCount;
}
void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) {
More information about the llvm-commits
mailing list