summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/COFF/Writer.cpp37
-rw-r--r--lld/test/COFF/gfids-export.s44
2 files changed, 69 insertions, 12 deletions
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index deb43768ddc..e5796d9bbd2 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -1304,6 +1304,25 @@ static void addSymbolToRVASet(SymbolRVASet &RVASet, Defined *S) {
RVASet.insert({C, Off});
}
+// Given a symbol, add it to the GFIDs table if it is a live, defined, function
+// symbol in an executable section.
+static void maybeAddAddressTakenFunction(SymbolRVASet &AddressTakenSyms,
+ Symbol *S) {
+ auto *D = dyn_cast_or_null<DefinedCOFF>(S);
+
+ // Ignore undefined symbols and references to non-functions (e.g. globals and
+ // labels).
+ if (!D ||
+ D->getCOFFSymbol().getComplexType() != COFF::IMAGE_SYM_DTYPE_FUNCTION)
+ return;
+
+ // Mark the symbol as address taken if it's in an executable section.
+ Chunk *RefChunk = D->getChunk();
+ OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
+ if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
+ addSymbolToRVASet(AddressTakenSyms, D);
+}
+
// Visit all relocations from all section contributions of this object file and
// mark the relocation target as address-taken.
static void markSymbolsWithRelocations(ObjFile *File,
@@ -1322,17 +1341,7 @@ static void markSymbolsWithRelocations(ObjFile *File,
continue;
Symbol *Ref = SC->File->getSymbol(Reloc.SymbolTableIndex);
- if (auto *D = dyn_cast_or_null<DefinedCOFF>(Ref)) {
- if (D->getCOFFSymbol().getComplexType() != COFF::IMAGE_SYM_DTYPE_FUNCTION)
- // Ignore relocations against non-functions (e.g. labels).
- continue;
-
- // Mark the symbol if it's in an executable section.
- Chunk *RefChunk = D->getChunk();
- OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
- if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
- addSymbolToRVASet(UsedSymbols, D);
- }
+ maybeAddAddressTakenFunction(UsedSymbols, Ref);
}
}
}
@@ -1359,7 +1368,11 @@ void Writer::createGuardCFTables() {
// Mark the image entry as address-taken.
if (Config->Entry)
- addSymbolToRVASet(AddressTakenSyms, cast<Defined>(Config->Entry));
+ maybeAddAddressTakenFunction(AddressTakenSyms, Config->Entry);
+
+ // Mark exported symbols in executable sections as address-taken.
+ for (Export &E : Config->Exports)
+ maybeAddAddressTakenFunction(AddressTakenSyms, E.Sym);
// Ensure sections referenced in the gfid table are 16-byte aligned.
for (const ChunkAndOffset &C : AddressTakenSyms)
diff --git a/lld/test/COFF/gfids-export.s b/lld/test/COFF/gfids-export.s
new file mode 100644
index 00000000000..87a4f4b47fa
--- /dev/null
+++ b/lld/test/COFF/gfids-export.s
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple x86_64-pc-win32 %s -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -guard:cf -dll -out:%t.dll -noentry
+# RUN: llvm-readobj -coff-load-config %t.dll | FileCheck %s --check-prefix=CHECK
+
+# There should be a single entry in the table for the exported symbol.
+#
+# CHECK: GuardFidTable [
+# CHECK-NEXT: 0x180001000
+# CHECK-NEXT: ]
+
+ .def func_export; .scl 2; .type 32; .endef
+ .globl func_export
+ .section .text,"xr",one_only,func_export
+ .p2align 4
+func_export:
+ movl $1, %eax
+ .globl label_export
+label_export:
+ movl $2, %eax
+ ret
+
+ .data
+ .globl data_export
+data_export:
+ .long 42
+
+ .section .drectve,"dr"
+ .ascii " /EXPORT:func_export"
+ .ascii " /EXPORT:label_export"
+ .ascii " /EXPORT:data_export"
+
+
+# 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 128, 1, 0
OpenPOWER on IntegriCloud