diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -74,10 +74,12 @@ 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 @@ 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 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -1996,6 +1996,8 @@ symtab->addAbsolute(mangle("__guard_iat_table"), 0); symtab->addAbsolute(mangle("__guard_longjmp_count"), 0); symtab->addAbsolute(mangle("__guard_longjmp_table"), 0); + symtab->addAbsolute(mangle("__guard_ehcont_count"), 0); + symtab->addAbsolute(mangle("__guard_ehcont_table"), 0); // Needed for MSVC 2017 15.5 CRT. symtab->addAbsolute(mangle("__enclave_config"), 0); diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -102,9 +102,15 @@ 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.h b/lld/COFF/InputFiles.h --- a/lld/COFF/InputFiles.h +++ b/lld/COFF/InputFiles.h @@ -146,6 +146,7 @@ ArrayRef getGuardFidChunks() { return guardFidChunks; } ArrayRef getGuardIATChunks() { return guardIATChunks; } ArrayRef getGuardLJmpChunks() { return guardLJmpChunks; } + ArrayRef getGuardEHContChunks() { return guardEHContChunks; } ArrayRef getSymbols() { return symbols; } MutableArrayRef getMutableSymbols() { return symbols; } @@ -184,7 +185,7 @@ 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 @@ std::vector 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 guardFidChunks; std::vector guardIATChunks; std::vector guardLJmpChunks; + std::vector 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/InputFiles.cpp b/lld/COFF/InputFiles.cpp --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -284,6 +284,8 @@ 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/Writer.cpp b/lld/COFF/Writer.cpp --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -1635,17 +1635,20 @@ SymbolRVASet giatsRVASet; std::vector 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 @@ "__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_ehcont_table", + "__guard_ehcont_count"); + // 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(flagSym)->setVA(guardFlags); } diff --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h --- a/llvm/include/llvm/Object/COFF.h +++ b/llvm/include/llvm/Object/COFF.h @@ -604,6 +604,7 @@ ProtectDelayLoadIAT = 0x00001000, DelayLoadIATSection = 0x00002000, // Delay load in separate section HasLongJmpTable = 0x00010000, + HasEHContTable = 0x00400000, FidTableHasFlags = 0x10000000, // Indicates that fid tables are 5 bytes };