[lld] r324306 - [COFF] Add minimal support for /guard:cf
Reid Kleckner via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 5 17:58:27 PST 2018
Author: rnk
Date: Mon Feb 5 17:58:26 2018
New Revision: 324306
URL: http://llvm.org/viewvc/llvm-project?rev=324306&view=rev
Log:
[COFF] Add minimal support for /guard:cf
Summary:
This patch adds some initial support for Windows control flow guard. At
the end of the day, the linker needs to synthesize a table of RVAs very
similar to the structured exception handler table (/safeseh).
Both /safeseh and /guard:cf take sections of symbol table indices
(.sxdata and .gfids$y) and turn them into RVA tables referenced by the
load config struct in the CRT through special symbols.
Reviewers: ruiu, amccarth
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D42592
Added:
lld/trunk/test/COFF/gfids-corrupt.s
lld/trunk/test/COFF/gfids-fallback.s
lld/trunk/test/COFF/gfids-gc.s
lld/trunk/test/COFF/gfids-icf.s
Modified:
lld/trunk/COFF/Chunks.cpp
lld/trunk/COFF/Chunks.h
lld/trunk/COFF/Config.h
lld/trunk/COFF/Driver.cpp
lld/trunk/COFF/Driver.h
lld/trunk/COFF/DriverUtils.cpp
lld/trunk/COFF/InputFiles.cpp
lld/trunk/COFF/InputFiles.h
lld/trunk/COFF/Options.td
lld/trunk/COFF/Writer.cpp
Modified: lld/trunk/COFF/Chunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.cpp?rev=324306&r1=324305&r2=324306&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.cpp (original)
+++ lld/trunk/COFF/Chunks.cpp Mon Feb 5 17:58:26 2018
@@ -453,12 +453,14 @@ void LocalImportChunk::writeTo(uint8_t *
}
}
-void SEHTableChunk::writeTo(uint8_t *Buf) const {
+void RVATableChunk::writeTo(uint8_t *Buf) const {
ulittle32_t *Begin = reinterpret_cast<ulittle32_t *>(Buf + OutputSectionOff);
size_t Cnt = 0;
- for (Defined *D : Syms)
- Begin[Cnt++] = D->getRVA();
+ for (const ChunkAndOffset &CO : Syms)
+ Begin[Cnt++] = CO.InputChunk->getRVA() + CO.Offset;
std::sort(Begin, Begin + Cnt);
+ assert(std::unique(Begin, Begin + Cnt) == Begin + Cnt &&
+ "RVA tables should be de-duplicated");
}
// Windows-specific. This class represents a block in .reloc section.
Modified: lld/trunk/COFF/Chunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.h?rev=324306&r1=324305&r2=324306&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.h (original)
+++ lld/trunk/COFF/Chunks.h Mon Feb 5 17:58:26 2018
@@ -320,17 +320,41 @@ private:
Defined *Sym;
};
-// Windows-specific.
-// A chunk for SEH table which contains RVAs of safe exception handler
-// functions. x86-only.
-class SEHTableChunk : public Chunk {
+// Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and
+// offset into the chunk. Order does not matter as the RVA table will be sorted
+// later.
+struct ChunkAndOffset {
+ Chunk *InputChunk;
+ uint32_t Offset;
+
+ struct DenseMapInfo {
+ static ChunkAndOffset getEmptyKey() {
+ return {llvm::DenseMapInfo<Chunk *>::getEmptyKey(), 0};
+ }
+ static ChunkAndOffset getTombstoneKey() {
+ return {llvm::DenseMapInfo<Chunk *>::getTombstoneKey(), 0};
+ }
+ static unsigned getHashValue(const ChunkAndOffset &CO) {
+ return llvm::DenseMapInfo<std::pair<Chunk *, uint32_t>>::getHashValue(
+ {CO.InputChunk, CO.Offset});
+ }
+ static bool isEqual(const ChunkAndOffset &LHS, const ChunkAndOffset &RHS) {
+ return LHS.InputChunk == RHS.InputChunk && LHS.Offset == RHS.Offset;
+ }
+ };
+};
+
+using SymbolRVASet = llvm::DenseSet<ChunkAndOffset>;
+
+// Table which contains symbol RVAs. Used for /safeseh and /guard:cf.
+class RVATableChunk : public Chunk {
public:
- explicit SEHTableChunk(std::set<Defined *> S) : Syms(std::move(S)) {}
+ explicit RVATableChunk(SymbolRVASet S) : Syms(std::move(S)) {}
size_t getSize() const override { return Syms.size() * 4; }
void writeTo(uint8_t *Buf) const override;
private:
- std::set<Defined *> Syms;
+ SymbolRVASet Syms;
};
// Windows-specific.
@@ -362,4 +386,10 @@ void applyBranch24T(uint8_t *Off, int32_
} // namespace coff
} // namespace lld
+namespace llvm {
+template <>
+struct DenseMapInfo<lld::coff::ChunkAndOffset>
+ : lld::coff::ChunkAndOffset::DenseMapInfo {};
+}
+
#endif
Modified: lld/trunk/COFF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Config.h?rev=324306&r1=324305&r2=324306&view=diff
==============================================================================
--- lld/trunk/COFF/Config.h (original)
+++ lld/trunk/COFF/Config.h Mon Feb 5 17:58:26 2018
@@ -112,6 +112,9 @@ struct Configuration {
bool SaveTemps = false;
+ // /guard:cf
+ bool GuardCF;
+
// Used for SafeSEH.
Symbol *SEHTable = nullptr;
Symbol *SEHCount = nullptr;
Modified: lld/trunk/COFF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=324306&r1=324305&r2=324306&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.cpp (original)
+++ lld/trunk/COFF/Driver.cpp Mon Feb 5 17:58:26 2018
@@ -983,6 +983,10 @@ void LinkerDriver::link(ArrayRef<const c
if (auto *Arg = Args.getLastArg(OPT_stack))
parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit);
+ // Handle /guard:cf
+ if (auto *Arg = Args.getLastArg(OPT_guard))
+ parseGuard(Arg->getValue());
+
// Handle /heap
if (auto *Arg = Args.getLastArg(OPT_heap))
parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit);
@@ -1285,11 +1289,9 @@ void LinkerDriver::link(ArrayRef<const c
Symtab->addAbsolute("___safe_se_handler_count", 0);
}
- // We do not support /guard:cf (control flow protection) yet.
- // Define CFG symbols anyway so that we can link MSVC 2015 CRT.
Symtab->addAbsolute(mangle("__guard_fids_count"), 0);
Symtab->addAbsolute(mangle("__guard_fids_table"), 0);
- Symtab->addAbsolute(mangle("__guard_flags"), 0x100);
+ Symtab->addAbsolute(mangle("__guard_flags"), 0);
Symtab->addAbsolute(mangle("__guard_iat_count"), 0);
Symtab->addAbsolute(mangle("__guard_iat_table"), 0);
Symtab->addAbsolute(mangle("__guard_longjmp_count"), 0);
@@ -1364,7 +1366,7 @@ void LinkerDriver::link(ArrayRef<const c
// Handle /safeseh.
if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) {
for (ObjFile *File : ObjFile::Instances)
- if (!File->SEHCompat)
+ if (!File->hasSafeSEH())
error("/safeseh: " + File->getName() + " is not compatible with SEH");
if (errorCount())
return;
Modified: lld/trunk/COFF/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.h?rev=324306&r1=324305&r2=324306&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.h (original)
+++ lld/trunk/COFF/Driver.h Mon Feb 5 17:58:26 2018
@@ -145,6 +145,8 @@ StringRef machineToStr(MachineTypes MT);
// Parses a string in the form of "<integer>[,<integer>]".
void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr);
+void parseGuard(StringRef Arg);
+
// Parses a string in the form of "<integer>[.<integer>]".
// Minor's default value is 0.
void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor);
Modified: lld/trunk/COFF/DriverUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DriverUtils.cpp?rev=324306&r1=324305&r2=324306&view=diff
==============================================================================
--- lld/trunk/COFF/DriverUtils.cpp (original)
+++ lld/trunk/COFF/DriverUtils.cpp Mon Feb 5 17:58:26 2018
@@ -128,6 +128,15 @@ void parseVersion(StringRef Arg, uint32_
fatal("invalid number: " + S2);
}
+void parseGuard(StringRef Arg) {
+ if (Arg.equals_lower("no"))
+ Config->GuardCF = false;
+ else if (Arg.equals_lower("cf"))
+ Config->GuardCF = true;
+ else
+ fatal("invalid argument to /GUARD: " + Arg);
+}
+
// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
uint32_t *Minor) {
Modified: lld/trunk/COFF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.cpp?rev=324306&r1=324305&r2=324306&view=diff
==============================================================================
--- lld/trunk/COFF/InputFiles.cpp (original)
+++ lld/trunk/COFF/InputFiles.cpp Mon Feb 5 17:58:26 2018
@@ -151,15 +151,7 @@ SectionChunk *ObjFile::readSection(uint3
if (auto EC = COFFObj->getSectionName(Sec, Name))
fatal("getSectionName failed: #" + Twine(SectionNumber) + ": " +
EC.message());
- if (Name == ".sxdata") {
- ArrayRef<uint8_t> Data;
- COFFObj->getSectionContents(Sec, Data);
- if (Data.size() % 4 != 0)
- fatal(".sxdata must be an array of symbol table indices");
- SXData = {reinterpret_cast<const ulittle32_t *>(Data.data()),
- Data.size() / 4};
- return nullptr;
- }
+
if (Name == ".drectve") {
ArrayRef<uint8_t> Data;
COFFObj->getSectionContents(Sec, Data);
@@ -191,6 +183,10 @@ SectionChunk *ObjFile::readSection(uint3
// linked in the regular manner.
if (C->isCodeView())
DebugChunks.push_back(C);
+ else if (Config->GuardCF && Name == ".gfids$y")
+ GuardFidChunks.push_back(C);
+ else if (Name == ".sxdata")
+ SXDataChunks.push_back(C);
else
Chunks.push_back(C);
@@ -308,10 +304,8 @@ Optional<Symbol *> ObjFile::createDefine
// Skip special symbols.
if (Name == "@comp.id")
return nullptr;
- // COFF spec 5.10.1. The .sxdata section.
if (Name == "@feat.00") {
- if (Sym.getValue() & 1)
- SEHCompat = true;
+ Feat00Flags = Sym.getValue();
return nullptr;
}
if (Sym.isExternal())
Modified: lld/trunk/COFF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.h?rev=324306&r1=324305&r2=324306&view=diff
==============================================================================
--- lld/trunk/COFF/InputFiles.h (original)
+++ lld/trunk/COFF/InputFiles.h Mon Feb 5 17:58:26 2018
@@ -110,6 +110,8 @@ public:
MachineTypes getMachineType() override;
ArrayRef<Chunk *> getChunks() { return Chunks; }
ArrayRef<SectionChunk *> getDebugChunks() { return DebugChunks; }
+ ArrayRef<SectionChunk *> getSXDataChunks() { return SXDataChunks; }
+ ArrayRef<SectionChunk *> getGuardFidChunks() { return GuardFidChunks; }
ArrayRef<Symbol *> getSymbols() { return Symbols; }
// Returns a Symbol object for the SymbolIndex'th symbol in the
@@ -123,13 +125,17 @@ public:
static std::vector<ObjFile *> Instances;
- // True if this object file is compatible with SEH.
- // COFF-specific and x86-only.
- bool SEHCompat = false;
-
- // The symbol table indexes of the safe exception handlers.
- // COFF-specific and x86-only.
- ArrayRef<llvm::support::ulittle32_t> SXData;
+ // Flags in the absolute @feat.00 symbol if it is present. These usually
+ // indicate if an object was compiled with certain security features enabled
+ // like stack guard, safeseh, /guard:cf, or other things.
+ uint32_t Feat00Flags = 0;
+
+ // True if this object file is compatible with SEH. COFF-specific and
+ // x86-only. COFF spec 5.10.1. The .sxdata section.
+ bool hasSafeSEH() { return Feat00Flags & 0x1; }
+
+ // True if this file was compiled with /guard:cf.
+ bool hasGuardCF() { return Feat00Flags & 0x800; }
// Pointer to the PDB module descriptor builder. Various debug info records
// will reference object files by "module index", which is here. Things like
@@ -165,6 +171,14 @@ private:
// CodeView debug info sections.
std::vector<SectionChunk *> DebugChunks;
+ // Chunks containing symbol table indices of exception handlers. Only used for
+ // 32-bit x86.
+ std::vector<SectionChunk *> SXDataChunks;
+
+ // Chunks containing symbol table indices of address taken symbols. These are
+ // not linked into the final binary when /guard:cf is set.
+ std::vector<SectionChunk *> GuardFidChunks;
+
// This vector contains the same chunks as Chunks, but they are
// indexed such that you can get a SectionChunk by section index.
// Nonexistent section indices are filled with null pointers.
Modified: lld/trunk/COFF/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Options.td?rev=324306&r1=324305&r2=324306&view=diff
==============================================================================
--- lld/trunk/COFF/Options.td (original)
+++ lld/trunk/COFF/Options.td Mon Feb 5 17:58:26 2018
@@ -28,6 +28,7 @@ def errorlimit : P<"errorlimit",
def export : P<"export", "Export a function">;
// No help text because /failifmismatch is not intended to be used by the user.
def failifmismatch : P<"failifmismatch", "">;
+def guard : P<"guard", "Control flow guard">;
def heap : P<"heap", "Size of the heap">;
def ignore : P<"ignore", "Specify warning codes to ignore">;
def implib : P<"implib", "Import library name">;
Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=324306&r1=324305&r2=324306&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Mon Feb 5 17:58:26 2018
@@ -26,6 +26,7 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Parallel.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/RandomNumberGenerator.h"
#include <algorithm>
#include <cstdio>
@@ -123,6 +124,12 @@ private:
void openFile(StringRef OutputPath);
template <typename PEHeaderTy> void writeHeader();
void createSEHTable(OutputSection *RData);
+ void createGFIDTable(OutputSection *RData);
+ void markSymbolsForRVATable(ObjFile *File,
+ ArrayRef<SectionChunk *> SymIdxChunks,
+ SymbolRVASet &TableSymbols);
+ void maybeAddRVATable(OutputSection *RData, SymbolRVASet TableSymbols,
+ StringRef TableSym, StringRef CountSym);
void setSectionPermissions();
void writeSections();
void writeBuildId();
@@ -146,7 +153,8 @@ private:
IdataContents Idata;
DelayLoadContents DelayIdata;
EdataContents Edata;
- SEHTableChunk *SEHTable = nullptr;
+ RVATableChunk *GuardFidsTable = nullptr;
+ RVATableChunk *SEHTable = nullptr;
Chunk *DebugDirectory = nullptr;
std::vector<Chunk *> DebugRecords;
@@ -428,7 +436,13 @@ void Writer::createMiscChunks() {
RData->addChunk(C);
}
- createSEHTable(RData);
+ // Create SEH table. x86-only.
+ if (Config->Machine == I386)
+ createSEHTable(RData);
+
+ // Create the guard function id table if requested.
+ if (Config->GuardCF)
+ createGFIDTable(RData);
}
// Create .idata section for the DLL-imported symbol table.
@@ -720,6 +734,8 @@ template <typename PEHeaderTy> void Writ
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
if (!Config->AllowIsolation)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;
+ if (Config->GuardCF)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF;
if (Config->Machine == I386 && !SEHTable &&
!Symtab->findUnderscore("_load_config_used"))
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH;
@@ -825,34 +841,146 @@ void Writer::openFile(StringRef Path) {
}
void Writer::createSEHTable(OutputSection *RData) {
- // Create SEH table. x86-only.
- if (Config->Machine != I386)
- return;
+ SymbolRVASet Handlers;
+ for (ObjFile *File : ObjFile::Instances) {
+ // FIXME: We should error here instead of earlier unless /safeseh:no was
+ // passed.
+ if (!File->hasSafeSEH())
+ return;
- std::set<Defined *> Handlers;
+ markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers);
+ }
+
+ maybeAddRVATable(RData, std::move(Handlers), "__safe_se_handler_table",
+ "__safe_se_handler_count");
+}
+
+// Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set
+// cannot contain duplicates. Therefore, the set is uniqued by Chunk and the
+// symbol's offset into that Chunk.
+static void addSymbolToRVASet(SymbolRVASet &RVASet, Defined *S) {
+ Chunk *C = S->getChunk();
+ if (auto *SC = dyn_cast<SectionChunk>(C))
+ C = SC->Repl; // Look through ICF replacement.
+ uint32_t Off = S->getRVA() - (C ? C->getRVA() : 0);
+ RVASet.insert({C, Off});
+}
+
+// Visit all relocations from all section contributions of this object file and
+// mark the relocation target as address-taken.
+static void markSymbolsWithRelocations(ObjFile *File,
+ SymbolRVASet &UsedSymbols) {
+ for (Chunk *C : File->getChunks()) {
+ // We only care about live section chunks. Common chunks and other chunks
+ // don't generally contain relocations.
+ SectionChunk *SC = dyn_cast<SectionChunk>(C);
+ if (!SC || !SC->isLive())
+ continue;
+
+ // Look for relocations in this section against symbols in executable output
+ // sections.
+ for (Symbol *Ref : SC->symbols()) {
+ // FIXME: Do further testing to see if the relocation type matters,
+ // especially for 32-bit where taking the address of something usually
+ // uses an absolute relocation instead of a relative one.
+ if (auto *D = dyn_cast_or_null<Defined>(Ref)) {
+ Chunk *RefChunk = D->getChunk();
+ OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
+ if (OS && OS->getPermissions() & IMAGE_SCN_MEM_EXECUTE)
+ addSymbolToRVASet(UsedSymbols, D);
+ }
+ }
+ }
+}
+// Create the guard function id table. This is a table of RVAs of all
+// address-taken functions. It is sorted and uniqued, just like the safe SEH
+// table.
+void Writer::createGFIDTable(OutputSection *RData) {
+ SymbolRVASet AddressTakenSyms;
for (ObjFile *File : ObjFile::Instances) {
- if (!File->SEHCompat)
- return;
- for (uint32_t I : File->SXData)
- if (Symbol *B = File->getSymbol(I))
- if (B->isLive())
- Handlers.insert(cast<Defined>(B));
+ // If the object was compiled with /guard:cf, the address taken symbols are
+ // in the .gfids$y sections. Otherwise, we approximate the set of address
+ // taken symbols by checking which symbols were used by relocations in live
+ // sections.
+ if (File->hasGuardCF())
+ markSymbolsForRVATable(File, File->getGuardFidChunks(), AddressTakenSyms);
+ else
+ markSymbolsWithRelocations(File, AddressTakenSyms);
+ }
+
+ // Mark the image entry as address-taken.
+ if (Config->Entry)
+ addSymbolToRVASet(AddressTakenSyms, cast<Defined>(Config->Entry));
+
+ maybeAddRVATable(RData, std::move(AddressTakenSyms), "__guard_fids_table",
+ "__guard_fids_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);
+ Symbol *FlagSym = Symtab->findUnderscore("__guard_flags");
+ cast<DefinedAbsolute>(FlagSym)->setVA(GuardFlags);
+}
+
+// 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
+// depend on the table size, so we can't directly build a set of integers.
+void Writer::markSymbolsForRVATable(ObjFile *File,
+ ArrayRef<SectionChunk *> SymIdxChunks,
+ SymbolRVASet &TableSymbols) {
+ 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.
+ // In this case, the associated gfids section is discarded, and we don't
+ // mark the virtual member functions as address-taken by the vtable.
+ if (!C->isLive())
+ continue;
+
+ // Validate that the contents look like symbol table indices.
+ ArrayRef<uint8_t> Data = C->getContents();
+ if (Data.size() % 4 != 0) {
+ warn("ignoring " + C->getSectionName() +
+ " symbol table index section in object " + toString(File));
+ continue;
+ }
+
+ // 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.
+ ArrayRef<ulittle32_t> SymIndices(
+ reinterpret_cast<const ulittle32_t *>(Data.data()), Data.size() / 4);
+ ArrayRef<Symbol *> ObjSymbols = File->getSymbols();
+ for (uint32_t SymIndex : SymIndices) {
+ if (SymIndex >= ObjSymbols.size()) {
+ warn("ignoring invalid symbol table index in section " +
+ C->getSectionName() + " in object " + toString(File));
+ continue;
+ }
+ if (Symbol *S = ObjSymbols[SymIndex]) {
+ if (S->isLive())
+ addSymbolToRVASet(TableSymbols, cast<Defined>(S));
+ }
+ }
}
+}
- if (Handlers.empty())
+// 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.
+void Writer::maybeAddRVATable(OutputSection *RData,
+ SymbolRVASet TableSymbols,
+ StringRef TableSym, StringRef CountSym) {
+ if (TableSymbols.empty())
return;
- SEHTable = make<SEHTableChunk>(Handlers);
- RData->addChunk(SEHTable);
+ RVATableChunk *TableChunk = make<RVATableChunk>(std::move(TableSymbols));
+ RData->addChunk(TableChunk);
- // Replace the absolute table symbol with a synthetic symbol pointing to the
- // SEHTable chunk so that we can emit base relocations for it and resolve
- // section relative relocations.
- Symbol *T = Symtab->find("___safe_se_handler_table");
- Symbol *C = Symtab->find("___safe_se_handler_count");
- replaceSymbol<DefinedSynthetic>(T, T->getName(), SEHTable);
- cast<DefinedAbsolute>(C)->setVA(SEHTable->getSize() / 4);
+ Symbol *T = Symtab->findUnderscore(TableSym);
+ Symbol *C = Symtab->findUnderscore(CountSym);
+ replaceSymbol<DefinedSynthetic>(T, T->getName(), TableChunk);
+ cast<DefinedAbsolute>(C)->setVA(TableChunk->getSize() / 4);
}
// Handles /section options to allow users to overwrite
Added: lld/trunk/test/COFF/gfids-corrupt.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/gfids-corrupt.s?rev=324306&view=auto
==============================================================================
--- lld/trunk/test/COFF/gfids-corrupt.s (added)
+++ lld/trunk/test/COFF/gfids-corrupt.s Mon Feb 5 17:58:26 2018
@@ -0,0 +1,83 @@
+# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
+# 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{{.*}}
+# ERRS: warning: ignoring invalid symbol table index in section .gfids$y in object {{.*}}gfids-corrupt{{.*}}
+
+# The table is arbitrary, really.
+# CHECK: ImageBase: 0x140000000
+# CHECK: LoadConfig [
+# CHECK: SEHandlerTable: 0x0
+# CHECK: SEHandlerCount: 0
+# CHECK: GuardCFCheckFunction: 0x0
+# CHECK: GuardCFCheckDispatch: 0x0
+# CHECK: GuardCFFunctionTable: 0x14000{{.*}}
+# CHECK: GuardCFFunctionCount: 2
+# CHECK: GuardFlags: 0x500
+# CHECK: GuardAddressTakenIatEntryTable: 0x0
+# CHECK: GuardAddressTakenIatEntryCount: 0
+# CHECK: GuardLongJumpTargetTable: 0x0
+# CHECK: GuardLongJumpTargetCount: 0
+# CHECK: ]
+# CHECK: GuardFidTable [
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: ]
+
+
+# Indicate that gfids are present.
+ .def @feat.00; .scl 3; .type 0; .endef
+ .globl @feat.00
+ at feat.00 = 0x800
+
+ .def f1; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,f1
+ .global f1
+f1:
+ movl $42, %eax
+ retq
+
+ .def f2; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,f2
+ .global f2
+f2:
+ movl $13, %eax
+ retq
+
+ .section .data,"dw",one_only,fp1
+ .globl fp1
+fp1:
+ .quad f1
+
+ .section .data,"dw",one_only,fp2
+ .globl fp2
+fp2:
+ .quad f2
+
+ .section .gfids$y,"dr",associative,fp1
+ .symidx f1
+ .byte 0
+
+ .section .gfids$y,"dr",associative,fp2
+ .symidx f2
+ .long 0x400
+
+ .def main; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,main
+ .globl main
+main:
+ callq *fp1(%rip)
+ callq *fp2(%rip)
+ xor %eax, %eax
+ retq
+
+ .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
Added: lld/trunk/test/COFF/gfids-fallback.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/gfids-fallback.s?rev=324306&view=auto
==============================================================================
--- lld/trunk/test/COFF/gfids-fallback.s (added)
+++ lld/trunk/test/COFF/gfids-fallback.s Mon Feb 5 17:58:26 2018
@@ -0,0 +1,96 @@
+# 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:cf -out:%t.exe -entry:main -opt:noref
+# 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: 3
+# CHECK: GuardFlags: 0x500
+# CHECK: GuardAddressTakenIatEntryTable: 0x0
+# CHECK: GuardAddressTakenIatEntryCount: 0
+# CHECK: GuardLongJumpTargetTable: 0x0
+# CHECK: GuardLongJumpTargetCount: 0
+# CHECK: ]
+# CHECK: GuardFidTable [
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: ]
+
+
+# Indicate that no gfids are present. All symbols used by relocations in this
+# file will be considered address-taken.
+ .def @feat.00; .scl 3; .type 0; .endef
+ .globl @feat.00
+ at feat.00 = 0
+
+ .def main; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,main
+ .globl main
+main:
+ subq $8, %rsp
+ leaq foo(%rip), %rdx
+ callq bar
+ movl $0, %eax
+ addq $8, %rsp
+ retq
+
+# Should not appear in gfids table.
+ .def baz; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,baz
+ .globl baz
+baz:
+ mov $1, %eax
+ retq
+
+ .def qux; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,qux
+ .globl qux
+qux:
+ mov $2, %eax
+ retq
+
+ .def quxx; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,quxx
+ .globl quxx
+quxx:
+ mov $3, %eax
+ retq
+
+# Load config.
+ .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
+
+# SPLITMARKER
+
+# Indicate that gfids are present. This file does not take any addresses.
+ .def @feat.00; .scl 3; .type 0; .endef
+ .globl @feat.00
+ at feat.00 = 0x800
+
+ .def foo; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,foo
+ .global foo
+foo:
+ movl $42, %eax
+ retq
+
+ .def bar; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,bar
+ .global bar
+bar:
+ movl $13, %eax
+ retq
Added: lld/trunk/test/COFF/gfids-gc.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/gfids-gc.s?rev=324306&view=auto
==============================================================================
--- lld/trunk/test/COFF/gfids-gc.s (added)
+++ lld/trunk/test/COFF/gfids-gc.s Mon Feb 5 17:58:26 2018
@@ -0,0 +1,128 @@
+# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
+# 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: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
+# /Gw (-fdata-sections) is enabled:
+# int f() { return 42; }
+# int g() { return 13; }
+# int (*fp1)() = &f;
+# int (*fp2)() = &g;
+# int main() {
+# return fp1();
+# }
+# Compile with 'cl -c -guard:cf -Gw -O1' and note the two associative .gfids$y
+# sections.
+
+# Expect 3 entries: main, f, and g.
+
+# CHECK-NOGC: ImageBase: 0x140000000
+# CHECK-NOGC: LoadConfig [
+# CHECK-NOGC: SEHandlerTable: 0x0
+# CHECK-NOGC: SEHandlerCount: 0
+# CHECK-NOGC: GuardCFCheckFunction: 0x0
+# CHECK-NOGC: GuardCFCheckDispatch: 0x0
+# CHECK-NOGC: GuardCFFunctionTable: 0x14000{{.*}}
+# CHECK-NOGC: GuardCFFunctionCount: 3
+# CHECK-NOGC: GuardFlags: 0x500
+# CHECK-NOGC: GuardAddressTakenIatEntryTable: 0x0
+# CHECK-NOGC: GuardAddressTakenIatEntryCount: 0
+# CHECK-NOGC: GuardLongJumpTargetTable: 0x0
+# CHECK-NOGC: GuardLongJumpTargetCount: 0
+# CHECK-NOGC: ]
+# CHECK-NOGC: GuardFidTable [
+# CHECK-NOGC-NEXT: 0x14000{{.*}}
+# CHECK-NOGC-NEXT: 0x14000{{.*}}
+# CHECK-NOGC-NEXT: 0x14000{{.*}}
+# CHECK-NOGC-NEXT: ]
+
+# Expect 2 entries: main and f. fp2 was discarded, so g was only used as a
+# direct call target.
+
+# CHECK-GC: ImageBase: 0x140000000
+# CHECK-GC: LoadConfig [
+# CHECK-GC: SEHandlerTable: 0x0
+# CHECK-GC: SEHandlerCount: 0
+# CHECK-GC: GuardCFCheckFunction: 0x0
+# CHECK-GC: GuardCFCheckDispatch: 0x0
+# CHECK-GC: GuardCFFunctionTable: 0x14000{{.*}}
+# CHECK-GC: GuardCFFunctionCount: 2
+# CHECK-GC: GuardFlags: 0x500
+# CHECK-GC: GuardAddressTakenIatEntryTable: 0x0
+# CHECK-GC: GuardAddressTakenIatEntryCount: 0
+# CHECK-GC: GuardLongJumpTargetTable: 0x0
+# CHECK-GC: GuardLongJumpTargetCount: 0
+# CHECK-GC: ]
+# CHECK-GC: GuardFidTable [
+# CHECK-GC-NEXT: 0x14000{{.*}}
+# CHECK-GC-NEXT: 0x14000{{.*}}
+# CHECK-GC-NEXT: ]
+
+
+# We need @feat.00 to have 0x800 to indicate .gfids are present.
+ .def @feat.00;
+ .scl 3;
+ .type 0;
+ .endef
+ .globl @feat.00
+ at feat.00 = 0x801
+
+ .def main;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,main
+ .globl main
+main:
+ # Call g directly so that it is not dead stripped.
+ callq g
+ rex64 jmpq *fp1(%rip)
+
+ .def f;
+ .scl 3;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,f
+f:
+ movl $42, %eax
+ retq
+
+ .section .data,"dw",one_only,fp1
+ .globl fp1
+fp1:
+ .quad f
+
+ .section .gfids$y,"dr",associative,fp1
+ .symidx f
+
+# Section GC will remove the following, so 'g' should not be present in the
+# guard fid table.
+
+ .def g;
+ .scl 3;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,g
+g:
+ movl $13, %eax
+ retq
+
+ .section .data,"dw",one_only,fp2
+ .globl fp2
+fp2:
+ .quad g
+
+ .section .gfids$y,"dr",associative,fp2
+ .symidx g
+
+ .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
Added: lld/trunk/test/COFF/gfids-icf.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/gfids-icf.s?rev=324306&view=auto
==============================================================================
--- lld/trunk/test/COFF/gfids-icf.s (added)
+++ lld/trunk/test/COFF/gfids-icf.s Mon Feb 5 17:58:26 2018
@@ -0,0 +1,87 @@
+# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
+# 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:
+# int icf1() { return 42; }
+# int icf2() { return 42; }
+# int (*fp1)() = &icf1;
+# int (*fp2)() = &icf2;
+# int main() {
+# return fp1();
+# return fp2();
+# }
+
+# 'icf1' and 'icf2' are address taken, but should be merged into one entry.
+# There are two entries in the table because 'main' is included.
+
+# CHECK: ImageBase: 0x140000000
+# CHECK: LoadConfig [
+# CHECK: SEHandlerTable: 0x0
+# CHECK: SEHandlerCount: 0
+# CHECK: GuardCFCheckFunction: 0x0
+# CHECK: GuardCFCheckDispatch: 0x0
+# CHECK: GuardCFFunctionTable: 0x14000{{.*}}
+# CHECK: GuardCFFunctionCount: 2
+# CHECK: GuardFlags: 0x500
+# CHECK: GuardAddressTakenIatEntryTable: 0x0
+# CHECK: GuardAddressTakenIatEntryCount: 0
+# CHECK: GuardLongJumpTargetTable: 0x0
+# CHECK: GuardLongJumpTargetCount: 0
+# CHECK: ]
+# CHECK: GuardFidTable [
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: 0x14000{{.*}}
+# CHECK-NEXT: ]
+
+
+# Indicate that gfids are present.
+ .def @feat.00; .scl 3; .type 0; .endef
+ .globl @feat.00
+ at feat.00 = 0x800
+
+ .def icf1; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,icf1
+ .global icf1
+icf1:
+ movl $42, %eax
+ retq
+
+ .def icf2; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,icf2
+ .global icf2
+icf2:
+ movl $42, %eax
+ retq
+
+# Take their two addresses.
+ .data
+ .globl fp1
+fp1:
+ .quad icf1
+ .globl fp2
+fp2:
+ .quad icf2
+
+ .section .gfids$y,"dr"
+ .symidx icf1
+ .symidx icf2
+
+ .def main; .scl 2; .type 32; .endef
+ .section .text,"xr",one_only,main
+ .globl main
+main:
+ callq *fp1(%rip)
+ callq *fp2(%rip)
+ xor %eax, %eax
+ retq
+
+ .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
More information about the llvm-commits
mailing list