[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