forked from OSchip/llvm-project
[CFGuard] Add address-taken IAT tables and delay-load support
This patch adds support for creating Guard Address-Taken IAT Entry Tables (.giats$y sections) in object files, matching the behavior of MSVC. These contain lists of address-taken imported functions, which are used by the linker to create the final GIATS table. Additionally, if any DLLs are delay-loaded, the linker must look through the .giats tables and add the respective load thunks of address-taken imports to the GFIDS table, as these are also valid call targets. Reviewed By: rnk Differential Revision: https://reviews.llvm.org/D87544
This commit is contained in:
parent
fcf70e1e3b
commit
ef4e971e5e
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "DLL.h"
|
||||
#include "Chunks.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
@ -653,9 +654,18 @@ void DelayLoadContents::create(Defined *h) {
|
|||
auto *c = make<HintNameChunk>(extName, 0);
|
||||
names.push_back(make<LookupChunk>(c));
|
||||
hintNames.push_back(c);
|
||||
// Add a syntentic symbol for this load thunk, using the "__imp_load"
|
||||
// prefix, in case this thunk needs to be added to the list of valid
|
||||
// call targets for Control Flow Guard.
|
||||
StringRef symName = saver.save("__imp_load_" + extName);
|
||||
s->loadThunkSym =
|
||||
cast<DefinedSynthetic>(symtab->addSynthetic(symName, t));
|
||||
}
|
||||
}
|
||||
thunks.push_back(tm);
|
||||
StringRef tmName =
|
||||
saver.save("__tailMerge_" + syms[0]->getDLLName().lower());
|
||||
symtab->addSynthetic(tmName, tm);
|
||||
// Terminate with null values.
|
||||
addresses.push_back(make<NullChunk>(8));
|
||||
names.push_back(make<NullChunk>(8));
|
||||
|
|
|
@ -131,7 +131,7 @@ bool ICF::assocEquals(const SectionChunk *a, const SectionChunk *b) {
|
|||
auto considerForICF = [](const SectionChunk &assoc) {
|
||||
StringRef Name = assoc.getSectionName();
|
||||
return !(Name.startswith(".debug") || Name == ".gfids$y" ||
|
||||
Name == ".gljmp$y");
|
||||
Name == ".giats$y" || Name == ".gljmp$y");
|
||||
};
|
||||
auto ra = make_filter_range(a->children(), considerForICF);
|
||||
auto rb = make_filter_range(b->children(), considerForICF);
|
||||
|
|
|
@ -280,6 +280,8 @@ SectionChunk *ObjFile::readSection(uint32_t sectionNumber,
|
|||
debugChunks.push_back(c);
|
||||
else if (name == ".gfids$y")
|
||||
guardFidChunks.push_back(c);
|
||||
else if (name == ".giats$y")
|
||||
guardIATChunks.push_back(c);
|
||||
else if (name == ".gljmp$y")
|
||||
guardLJmpChunks.push_back(c);
|
||||
else if (name == ".sxdata")
|
||||
|
|
|
@ -144,6 +144,7 @@ public:
|
|||
ArrayRef<SectionChunk *> getDebugChunks() { return debugChunks; }
|
||||
ArrayRef<SectionChunk *> getSXDataChunks() { return sxDataChunks; }
|
||||
ArrayRef<SectionChunk *> getGuardFidChunks() { return guardFidChunks; }
|
||||
ArrayRef<SectionChunk *> getGuardIATChunks() { return guardIATChunks; }
|
||||
ArrayRef<SectionChunk *> getGuardLJmpChunks() { return guardLJmpChunks; }
|
||||
ArrayRef<Symbol *> getSymbols() { return symbols; }
|
||||
|
||||
|
@ -283,9 +284,11 @@ private:
|
|||
// 32-bit x86.
|
||||
std::vector<SectionChunk *> sxDataChunks;
|
||||
|
||||
// Chunks containing symbol table indices of address taken symbols and longjmp
|
||||
// targets. These are not linked into the final binary when /guard:cf is set.
|
||||
// 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.
|
||||
std::vector<SectionChunk *> guardFidChunks;
|
||||
std::vector<SectionChunk *> guardIATChunks;
|
||||
std::vector<SectionChunk *> guardLJmpChunks;
|
||||
|
||||
// This vector contains a list of all symbols defined or referenced by this
|
||||
|
|
|
@ -343,6 +343,13 @@ public:
|
|||
uint16_t getOrdinal() { return file->hdr->OrdinalHint; }
|
||||
|
||||
ImportFile *file;
|
||||
|
||||
// This is a pointer to the synthetic symbol associated with the load thunk
|
||||
// for this symbol that will be called if the DLL is delay-loaded. This is
|
||||
// needed for Control Flow Guard because if this DefinedImportData symbol is a
|
||||
// valid call target, the corresponding load thunk must also be marked as a
|
||||
// valid call target.
|
||||
DefinedSynthetic *loadThunkSym;
|
||||
};
|
||||
|
||||
// This class represents a symbol for a jump table entry which jumps
|
||||
|
|
|
@ -227,6 +227,9 @@ private:
|
|||
void markSymbolsForRVATable(ObjFile *file,
|
||||
ArrayRef<SectionChunk *> symIdxChunks,
|
||||
SymbolRVASet &tableSymbols);
|
||||
void getSymbolsFromSections(ObjFile *file,
|
||||
ArrayRef<SectionChunk *> symIdxChunks,
|
||||
std::vector<Symbol *> &symbols);
|
||||
void maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
|
||||
StringRef countSym);
|
||||
void setSectionPermissions();
|
||||
|
@ -605,8 +608,9 @@ void Writer::run() {
|
|||
|
||||
createImportTables();
|
||||
createSections();
|
||||
createMiscChunks();
|
||||
appendImportThunks();
|
||||
// Import thunks must be added before the Control Flow Guard tables are added.
|
||||
createMiscChunks();
|
||||
createExportTable();
|
||||
mergeSections();
|
||||
removeUnusedSections();
|
||||
|
@ -1618,6 +1622,8 @@ static void markSymbolsWithRelocations(ObjFile *file,
|
|||
// table.
|
||||
void Writer::createGuardCFTables() {
|
||||
SymbolRVASet addressTakenSyms;
|
||||
SymbolRVASet giatsRVASet;
|
||||
std::vector<Symbol *> giatsSymbols;
|
||||
SymbolRVASet longJmpTargets;
|
||||
for (ObjFile *file : ObjFile::instances) {
|
||||
// If the object was compiled with /guard:cf, the address taken symbols
|
||||
|
@ -1627,6 +1633,8 @@ void Writer::createGuardCFTables() {
|
|||
// 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);
|
||||
} else {
|
||||
markSymbolsWithRelocations(file, addressTakenSyms);
|
||||
|
@ -1641,6 +1649,16 @@ void Writer::createGuardCFTables() {
|
|||
for (Export &e : config->exports)
|
||||
maybeAddAddressTakenFunction(addressTakenSyms, e.sym);
|
||||
|
||||
// For each entry in the .giats table, check if it has a corresponding load
|
||||
// thunk (e.g. because the DLL that defines it will be delay-loaded) and, if
|
||||
// so, add the load thunk to the address taken (.gfids) table.
|
||||
for (Symbol *s : giatsSymbols) {
|
||||
if (auto *di = dyn_cast<DefinedImportData>(s)) {
|
||||
if (di->loadThunkSym)
|
||||
addSymbolToRVASet(addressTakenSyms, di->loadThunkSym);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure sections referenced in the gfid table are 16-byte aligned.
|
||||
for (const ChunkAndOffset &c : addressTakenSyms)
|
||||
if (c.inputChunk->getAlignment() < 16)
|
||||
|
@ -1649,6 +1667,10 @@ void Writer::createGuardCFTables() {
|
|||
maybeAddRVATable(std::move(addressTakenSyms), "__guard_fids_table",
|
||||
"__guard_fids_count");
|
||||
|
||||
// Add the Guard Address Taken IAT Entry Table (.giats).
|
||||
maybeAddRVATable(std::move(giatsRVASet), "__guard_iat_table",
|
||||
"__guard_iat_count");
|
||||
|
||||
// Add the longjmp target table unless the user told us not to.
|
||||
if (config->guardCF == GuardCFLevel::Full)
|
||||
maybeAddRVATable(std::move(longJmpTargets), "__guard_longjmp_table",
|
||||
|
@ -1665,11 +1687,11 @@ void Writer::createGuardCFTables() {
|
|||
}
|
||||
|
||||
// Take a list of input sections containing symbol table indices and add those
|
||||
// symbols to an RVA table. The challenge is that symbol RVAs are not known and
|
||||
// symbols to a vector. The challenge is that symbol RVAs are not known and
|
||||
// depend on the table size, so we can't directly build a set of integers.
|
||||
void Writer::markSymbolsForRVATable(ObjFile *file,
|
||||
void Writer::getSymbolsFromSections(ObjFile *file,
|
||||
ArrayRef<SectionChunk *> symIdxChunks,
|
||||
SymbolRVASet &tableSymbols) {
|
||||
std::vector<Symbol *> &symbols) {
|
||||
for (SectionChunk *c : symIdxChunks) {
|
||||
// Skip sections discarded by linker GC. This comes up when a .gfids section
|
||||
// is associated with something like a vtable and the vtable is discarded.
|
||||
|
@ -1687,7 +1709,7 @@ void Writer::markSymbolsForRVATable(ObjFile *file,
|
|||
}
|
||||
|
||||
// Read each symbol table index and check if that symbol was included in the
|
||||
// final link. If so, add it to the table symbol set.
|
||||
// final link. If so, add it to the vector of symbols.
|
||||
ArrayRef<ulittle32_t> symIndices(
|
||||
reinterpret_cast<const ulittle32_t *>(data.data()), data.size() / 4);
|
||||
ArrayRef<Symbol *> objSymbols = file->getSymbols();
|
||||
|
@ -1699,12 +1721,24 @@ void Writer::markSymbolsForRVATable(ObjFile *file,
|
|||
}
|
||||
if (Symbol *s = objSymbols[symIndex]) {
|
||||
if (s->isLive())
|
||||
addSymbolToRVASet(tableSymbols, cast<Defined>(s));
|
||||
symbols.push_back(cast<Symbol>(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Take a list of input sections containing symbol table indices and add those
|
||||
// symbols to an RVA table.
|
||||
void Writer::markSymbolsForRVATable(ObjFile *file,
|
||||
ArrayRef<SectionChunk *> symIdxChunks,
|
||||
SymbolRVASet &tableSymbols) {
|
||||
std::vector<Symbol *> syms;
|
||||
getSymbolsFromSections(file, symIdxChunks, syms);
|
||||
|
||||
for (Symbol *s : syms)
|
||||
addSymbolToRVASet(tableSymbols, cast<Defined>(s));
|
||||
}
|
||||
|
||||
// Replace the absolute table symbol with a synthetic symbol pointing to
|
||||
// tableChunk so that we can emit base relocations for it and resolve section
|
||||
// relative relocations.
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
# REQUIRES: x86
|
||||
|
||||
# Make a DLL that exports exportfn1.
|
||||
# RUN: yaml2obj %p/Inputs/export.yaml -o %basename_t-exp.obj
|
||||
# RUN: lld-link /out:%basename_t-exp.dll /dll %basename_t-exp.obj /export:exportfn1 /implib:%basename_t-exp.lib
|
||||
|
||||
# Make an object file that imports exportfn1.
|
||||
# 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: llvm-readobj --file-headers --coff-load-config %basename_t-nodelay.exe | FileCheck %s --check-prefix CHECK
|
||||
|
||||
# CHECK: ImageBase: 0x140000000
|
||||
# CHECK: LoadConfig [
|
||||
# CHECK: GuardCFFunctionTable: 0x140002114
|
||||
# CHECK: GuardCFFunctionCount: 1
|
||||
# CHECK: GuardFlags: 0x10500
|
||||
# CHECK: GuardAddressTakenIatEntryTable: 0x140002118
|
||||
# CHECK: GuardAddressTakenIatEntryCount: 1
|
||||
# CHECK: ]
|
||||
# CHECK: GuardFidTable [
|
||||
# CHECK-NEXT: 0x14000{{.*}}
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK: GuardIatTable [
|
||||
# CHECK-NEXT: 0x14000{{.*}}
|
||||
# CHECK-NEXT: ]
|
||||
|
||||
|
||||
# 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: llvm-readobj --file-headers --coff-load-config %basename_t-delay.exe | FileCheck %s --check-prefix DELAY-CHECK
|
||||
|
||||
# DELAY-CHECK: ImageBase: 0x140000000
|
||||
# DELAY-CHECK: LoadConfig [
|
||||
# DELAY-CHECK: GuardCFFunctionTable: 0x140002114
|
||||
# DELAY-CHECK: GuardCFFunctionCount: 2
|
||||
# DELAY-CHECK: GuardFlags: 0x10500
|
||||
# DELAY-CHECK: GuardAddressTakenIatEntryTable: 0x14000211C
|
||||
# DELAY-CHECK: GuardAddressTakenIatEntryCount: 1
|
||||
# DELAY-CHECK: ]
|
||||
# DELAY-CHECK: GuardFidTable [
|
||||
# DELAY-CHECK-NEXT: 0x14000{{.*}}
|
||||
# DELAY-CHECK-NEXT: 0x14000{{.*}}
|
||||
# DELAY-CHECK-NEXT: ]
|
||||
# DELAY-CHECK: GuardIatTable [
|
||||
# DELAY-CHECK-NEXT: 0x14000{{.*}}
|
||||
# DELAY-CHECK-NEXT: ]
|
||||
|
||||
|
||||
# This assembly is reduced from C code like:
|
||||
# __declspec(noinline)
|
||||
# void IndirectCall(BOOL (func)(HANDLE)) {
|
||||
# (*func)(NULL);
|
||||
# }
|
||||
# int main(int argc, char** argv) {
|
||||
# IndirectCall(exportfn1);
|
||||
# }
|
||||
|
||||
.text
|
||||
.def @feat.00;
|
||||
.scl 3;
|
||||
.type 0;
|
||||
.endef
|
||||
.globl @feat.00
|
||||
.set @feat.00, 2048
|
||||
.def IndirectCall; .scl 2; .type 32; .endef
|
||||
.globl IndirectCall # -- Begin function IndirectCall
|
||||
.p2align 4, 0x90
|
||||
IndirectCall: # @IndirectCall
|
||||
# %bb.0:
|
||||
subq $40, %rsp
|
||||
movq %rcx, 32(%rsp)
|
||||
movq 32(%rsp), %rax
|
||||
movq %rax, %rdx # This would otherwise have be: movq __guard_dispatch_icall_fptr(%rip), %rdx
|
||||
xorl %ecx, %ecx
|
||||
callq *%rdx
|
||||
nop
|
||||
addq $40, %rsp
|
||||
retq
|
||||
# -- End function
|
||||
.def main; .scl 2; .type 32; .endef
|
||||
.globl main # -- Begin function main
|
||||
.p2align 4, 0x90
|
||||
main: # @main
|
||||
# %bb.0:
|
||||
subq $56, %rsp
|
||||
movq __imp_exportfn1(%rip), %rax
|
||||
movq %rdx, 48(%rsp)
|
||||
movl %ecx, 44(%rsp)
|
||||
movq %rax, %rcx
|
||||
callq IndirectCall
|
||||
xorl %eax, %eax
|
||||
addq $56, %rsp
|
||||
retq
|
||||
# -- End function
|
||||
.section .gfids$y,"dr"
|
||||
.section .giats$y,"dr"
|
||||
.symidx __imp_exportfn1
|
||||
.section .gljmp$y,"dr"
|
||||
|
||||
# Load configuration directory entry (winnt.h _IMAGE_LOAD_CONFIG_DIRECTORY64).
|
||||
# The linker will define the __guard_* symbols.
|
||||
.section .rdata,"dr"
|
||||
.globl _load_config_used
|
||||
_load_config_used:
|
||||
.long 256
|
||||
.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_fids_count
|
||||
.fill 84, 1, 0
|
|
@ -215,6 +215,7 @@ protected:
|
|||
MCSection *XDataSection = nullptr;
|
||||
MCSection *SXDataSection = nullptr;
|
||||
MCSection *GFIDsSection = nullptr;
|
||||
MCSection *GIATsSection = nullptr;
|
||||
MCSection *GLJMPSection = nullptr;
|
||||
|
||||
// XCOFF specific sections
|
||||
|
@ -398,6 +399,7 @@ public:
|
|||
MCSection *getXDataSection() const { return XDataSection; }
|
||||
MCSection *getSXDataSection() const { return SXDataSection; }
|
||||
MCSection *getGFIDsSection() const { return GFIDsSection; }
|
||||
MCSection *getGIATsSection() const { return GIATsSection; }
|
||||
MCSection *getGLJMPSection() const { return GLJMPSection; }
|
||||
|
||||
// XCOFF specific sections
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for writing the metadata for Windows Control Flow
|
||||
// Guard, including address-taken functions, and valid longjmp targets.
|
||||
// Guard, including address-taken functions and valid longjmp targets.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
@ -17,8 +17,8 @@
|
|||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/MachineOperand.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCObjectFileInfo.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
|
@ -78,20 +78,49 @@ static bool isPossibleIndirectCallTarget(const Function *F) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/// Returns true if this function should be added to the Guard Address Taken IAT
|
||||
/// Entry Table (GIATs) instead of the Guard Function ID Table (GFIDs).
|
||||
static bool isIATAddressTaken(const Function *F) {
|
||||
if (F->hasDLLImportStorageClass()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WinCFGuard::endModule() {
|
||||
const Module *M = Asm->MMI->getModule();
|
||||
std::vector<const Function *> Functions;
|
||||
for (const Function &F : *M)
|
||||
if (isPossibleIndirectCallTarget(&F))
|
||||
Functions.push_back(&F);
|
||||
if (Functions.empty() && LongjmpTargets.empty())
|
||||
std::vector<const Function *> GFIDsEntries;
|
||||
std::vector<const Function *> GIATsEntries;
|
||||
for (const Function &F : *M) {
|
||||
if (isPossibleIndirectCallTarget(&F)) {
|
||||
if (isIATAddressTaken(&F)) {
|
||||
// If the possible call target is reached via the IAT, add it to the
|
||||
// GIATs table instead of the GFIDs table.
|
||||
GIATsEntries.push_back(&F);
|
||||
} else {
|
||||
// Otherwise add it to the GFIDs table.
|
||||
GFIDsEntries.push_back(&F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GFIDsEntries.empty() && GIATsEntries.empty() && LongjmpTargets.empty())
|
||||
return;
|
||||
|
||||
// Emit the symbol index of each GFIDs entry to form the GFIDs table.
|
||||
auto &OS = *Asm->OutStreamer;
|
||||
OS.SwitchSection(Asm->OutContext.getObjectFileInfo()->getGFIDsSection());
|
||||
for (const Function *F : Functions)
|
||||
for (const Function *F : GFIDsEntries)
|
||||
OS.EmitCOFFSymbolIndex(Asm->getSymbol(F));
|
||||
|
||||
// Emit the symbol index of each longjmp target.
|
||||
// Emit the symbol index of each GIATs entry to form the GIATs table.
|
||||
OS.SwitchSection(Asm->OutContext.getObjectFileInfo()->getGIATsSection());
|
||||
for (const Function *F : GIATsEntries) {
|
||||
OS.EmitCOFFSymbolIndex(Asm->OutContext.getOrCreateSymbol(
|
||||
Twine("__imp_") + Asm->getSymbol(F)->getName()));
|
||||
}
|
||||
|
||||
// Emit the symbol index of each longjmp target to form the GLJMP table.
|
||||
OS.SwitchSection(Asm->OutContext.getObjectFileInfo()->getGLJMPSection());
|
||||
for (const MCSymbol *S : LongjmpTargets) {
|
||||
OS.EmitCOFFSymbolIndex(S);
|
||||
|
|
|
@ -752,6 +752,11 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) {
|
|||
COFF::IMAGE_SCN_MEM_READ,
|
||||
SectionKind::getMetadata());
|
||||
|
||||
GIATsSection = Ctx->getCOFFSection(".giats$y",
|
||||
COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
|
||||
COFF::IMAGE_SCN_MEM_READ,
|
||||
SectionKind::getMetadata());
|
||||
|
||||
GLJMPSection = Ctx->getCOFFSection(".gljmp$y",
|
||||
COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
|
||||
COFF::IMAGE_SCN_MEM_READ,
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
; RUN: llc < %s -mtriple=x86_64-pc-windows-msvc | FileCheck %s
|
||||
; Control Flow Guard is currently only available on Windows
|
||||
|
||||
declare dllimport i32 @target_func()
|
||||
|
||||
; Test address-taken functions from imported DLLs are added to the
|
||||
; Guard Address-Taken IAT Entry table (.giats).
|
||||
define i32 @func_cf_giats() {
|
||||
entry:
|
||||
%func_ptr = alloca i32 ()*, align 8
|
||||
store i32 ()* @target_func, i32 ()** %func_ptr, align 8
|
||||
%0 = load i32 ()*, i32 ()** %func_ptr, align 8
|
||||
%1 = call i32 %0()
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
!llvm.module.flags = !{!0}
|
||||
!0 = !{i32 2, !"cfguard", i32 2}
|
||||
|
||||
; CHECK-LABEL: .section .giats$y,"dr"
|
||||
; CHECK-NEXT: .symidx __imp_target_func
|
||||
; CHECK-NOT: .symidx
|
|
@ -67,6 +67,8 @@ struct LoadConfigTables {
|
|||
uint32_t GuardFlags = 0;
|
||||
uint64_t GuardFidTableVA = 0;
|
||||
uint64_t GuardFidTableCount = 0;
|
||||
uint64_t GuardIatTableVA = 0;
|
||||
uint64_t GuardIatTableCount = 0;
|
||||
uint64_t GuardLJmpTableVA = 0;
|
||||
uint64_t GuardLJmpTableCount = 0;
|
||||
};
|
||||
|
@ -804,6 +806,11 @@ void COFFDumper::printCOFFLoadConfig() {
|
|||
}
|
||||
}
|
||||
|
||||
if (Tables.GuardIatTableVA) {
|
||||
ListScope LS(W, "GuardIatTable");
|
||||
printRVATable(Tables.GuardIatTableVA, Tables.GuardIatTableCount, 4);
|
||||
}
|
||||
|
||||
if (Tables.GuardLJmpTableVA) {
|
||||
ListScope LS(W, "GuardLJmpTable");
|
||||
printRVATable(Tables.GuardLJmpTableVA, Tables.GuardLJmpTableCount, 4);
|
||||
|
@ -888,6 +895,9 @@ void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) {
|
|||
Conf->GuardRFVerifyStackPointerFunctionPointer);
|
||||
W.printHex("HotPatchTableOffset", Conf->HotPatchTableOffset);
|
||||
|
||||
Tables.GuardIatTableVA = Conf->GuardAddressTakenIatEntryTable;
|
||||
Tables.GuardIatTableCount = Conf->GuardAddressTakenIatEntryCount;
|
||||
|
||||
Tables.GuardLJmpTableVA = Conf->GuardLongJumpTargetTable;
|
||||
Tables.GuardLJmpTableCount = Conf->GuardLongJumpTargetCount;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue