summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/COFF/Driver.cpp6
-rw-r--r--lld/COFF/SymbolTable.cpp4
-rw-r--r--lld/COFF/SymbolTable.h2
-rw-r--r--lld/COFF/Symbols.h38
-rw-r--r--lld/COFF/Writer.cpp55
-rw-r--r--lld/test/COFF/pdb-safeseh.yaml85
-rw-r--r--lld/test/COFF/safeseh-diag-feat.test (renamed from lld/test/COFF/safeseh.test)0
-rw-r--r--lld/test/COFF/safeseh.s60
8 files changed, 213 insertions, 37 deletions
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index b5c0ac2200c..22efb312ae4 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -1026,10 +1026,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (Config->ImageBase == uint64_t(-1))
Config->ImageBase = getDefaultImageBase();
- Symtab.addRelative(mangle("__ImageBase"), 0);
+ Symtab.addSynthetic(mangle("__ImageBase"), nullptr);
if (Config->Machine == I386) {
- Config->SEHTable = Symtab.addRelative("___safe_se_handler_table", 0);
- Config->SEHCount = Symtab.addAbsolute("___safe_se_handler_count", 0);
+ Symtab.addAbsolute("___safe_se_handler_table", 0);
+ Symtab.addAbsolute("___safe_se_handler_count", 0);
}
// We do not support /guard:cf (control flow protection) yet.
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 5089825e62c..c06e42bb114 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -219,13 +219,13 @@ Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) {
return S;
}
-Symbol *SymbolTable::addRelative(StringRef N, uint64_t VA) {
+Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body()))
- replaceBody<DefinedRelative>(S, N, VA);
+ replaceBody<DefinedSynthetic>(S, N, C);
else if (!isa<DefinedCOFF>(S->body()))
reportDuplicate(S, nullptr);
return S;
diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index 0aa8a4593b5..ea74678c28d 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -85,7 +85,7 @@ public:
// Creates an Undefined symbol for a given name.
SymbolBody *addUndefined(StringRef Name);
- Symbol *addRelative(StringRef N, uint64_t VA);
+ Symbol *addSynthetic(StringRef N, Chunk *C);
Symbol *addAbsolute(StringRef N, uint64_t VA);
Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias);
diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h
index 828744b8ff3..feebb6dde1f 100644
--- a/lld/COFF/Symbols.h
+++ b/lld/COFF/Symbols.h
@@ -50,13 +50,13 @@ public:
DefinedImportThunkKind,
DefinedImportDataKind,
DefinedAbsoluteKind,
- DefinedRelativeKind,
+ DefinedSyntheticKind,
UndefinedKind,
LazyKind,
LastDefinedCOFFKind = DefinedCommonKind,
- LastDefinedKind = DefinedRelativeKind,
+ LastDefinedKind = DefinedSyntheticKind,
};
Kind kind() const { return static_cast<Kind>(SymbolKind); }
@@ -112,11 +112,11 @@ public:
// Returns the RVA relative to the beginning of the output section.
// Used to implement SECREL relocation type.
- uint64_t getSecrel();
+ uint32_t getSecrel();
// Returns the output section index.
// Used to implement SECTION relocation type.
- uint64_t getSectionIndex();
+ uint16_t getSectionIndex();
// Returns true if this symbol points to an executable (e.g. .text) section.
// Used to implement ARM relocations.
@@ -167,6 +167,7 @@ public:
bool isCOMDAT() { return IsCOMDAT; }
SectionChunk *getChunk() { return *Data; }
uint32_t getValue() { return Sym->Value; }
+ uint32_t getSecrel();
private:
SectionChunk **Data;
@@ -221,24 +222,25 @@ private:
uint64_t VA;
};
-// This is a kind of absolute symbol but relative to the image base.
-// Unlike absolute symbols, relocations referring this kind of symbols
-// are subject of the base relocation. This type is used rarely --
-// mainly for __ImageBase.
-class DefinedRelative : public Defined {
+// This symbol is used for linker-synthesized symbols like __ImageBase and
+// __safe_se_handler_table.
+class DefinedSynthetic : public Defined {
public:
- explicit DefinedRelative(StringRef Name, uint64_t V = 0)
- : Defined(DefinedRelativeKind, Name), RVA(V) {}
+ explicit DefinedSynthetic(StringRef Name, Chunk *C)
+ : Defined(DefinedSyntheticKind, Name), C(C) {}
static bool classof(const SymbolBody *S) {
- return S->kind() == DefinedRelativeKind;
+ return S->kind() == DefinedSyntheticKind;
}
- uint64_t getRVA() { return RVA; }
- void setRVA(uint64_t V) { RVA = V; }
+ // A null chunk indicates that this is __ImageBase. Otherwise, this is some
+ // other synthesized chunk, like SEHTableChunk.
+ uint32_t getRVA() const { return C ? C->getRVA() : 0; }
+ uint32_t getSecrel() const { return C ? C->OutputSectionOff : 0; }
+ Chunk *getChunk() const { return C; }
private:
- uint64_t RVA;
+ Chunk *C;
};
// This class represents a symbol defined in an archive file. It is
@@ -355,8 +357,8 @@ inline uint64_t Defined::getRVA() {
switch (kind()) {
case DefinedAbsoluteKind:
return cast<DefinedAbsolute>(this)->getRVA();
- case DefinedRelativeKind:
- return cast<DefinedRelative>(this)->getRVA();
+ case DefinedSyntheticKind:
+ return cast<DefinedSynthetic>(this)->getRVA();
case DefinedImportDataKind:
return cast<DefinedImportData>(this)->getRVA();
case DefinedImportThunkKind:
@@ -391,7 +393,7 @@ struct Symbol {
// AlignedCharArrayUnion gives us a struct with a char array field that is
// large and aligned enough to store any derived class of SymbolBody.
llvm::AlignedCharArrayUnion<
- DefinedRegular, DefinedCommon, DefinedAbsolute, DefinedRelative, Lazy,
+ DefinedRegular, DefinedCommon, DefinedAbsolute, DefinedSynthetic, Lazy,
Undefined, DefinedImportData, DefinedImportThunk, DefinedLocalImport>
Body;
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 083839c2bab..03e5d4d675b 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -210,17 +210,36 @@ void OutputSection::writeHeaderTo(uint8_t *Buf) {
}
}
-uint64_t Defined::getSecrel() {
- if (auto *D = dyn_cast<DefinedRegular>(this))
- return getRVA() - D->getChunk()->getOutputSection()->getRVA();
+uint32_t Defined::getSecrel() {
+ assert(this);
+ switch (kind()) {
+ case DefinedRegularKind:
+ return cast<DefinedRegular>(this)->getSecrel();
+ case DefinedSyntheticKind:
+ return cast<DefinedSynthetic>(this)->getSecrel();
+ default:
+ break;
+ }
fatal("SECREL relocation points to a non-regular symbol: " + toString(*this));
}
-uint64_t Defined::getSectionIndex() {
+uint32_t DefinedRegular::getSecrel() {
+ assert(getChunk()->isLive() && "relocation against discarded section");
+ uint64_t Diff = getRVA() - getChunk()->getOutputSection()->getRVA();
+ assert(Diff < UINT32_MAX && "section offset too large");
+ return (uint32_t)Diff;
+}
+
+uint16_t Defined::getSectionIndex() {
if (auto *D = dyn_cast<DefinedRegular>(this))
return D->getChunk()->getOutputSection()->SectionIndex;
if (isa<DefinedAbsolute>(this))
return DefinedAbsolute::OutputSectionIndex;
+ if (auto *D = dyn_cast<DefinedSynthetic>(this)) {
+ if (!D->getChunk())
+ return 0;
+ return D->getChunk()->getOutputSection()->SectionIndex;
+ }
fatal("SECTION relocation points to a non-regular symbol: " +
toString(*this));
}
@@ -348,12 +367,19 @@ void Writer::createMiscChunks() {
for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) {
if (!File->SEHCompat)
return;
- for (SymbolBody *B : File->SEHandlers)
- Handlers.insert(cast<Defined>(B));
+ for (SymbolBody *B : File->SEHandlers) {
+ // Make sure the handler is still live. Assume all handlers are regular
+ // symbols.
+ auto *D = dyn_cast<DefinedRegular>(B);
+ if (D && D->getChunk()->isLive())
+ Handlers.insert(D);
+ }
}
- SEHTable = make<SEHTableChunk>(Handlers);
- RData->addChunk(SEHTable);
+ if (!Handlers.empty()) {
+ SEHTable = make<SEHTableChunk>(Handlers);
+ RData->addChunk(SEHTable);
+ }
}
// Create .idata section for the DLL-imported symbol table.
@@ -445,7 +471,7 @@ size_t Writer::addEntryToStringTable(StringRef Str) {
Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
// Relative symbols are unrepresentable in a COFF symbol table.
- if (isa<DefinedRelative>(Def))
+ if (isa<DefinedSynthetic>(Def))
return None;
if (auto *D = dyn_cast<DefinedRegular>(Def)) {
@@ -758,10 +784,13 @@ void Writer::openFile(StringRef Path) {
void Writer::fixSafeSEHSymbols() {
if (!SEHTable)
return;
- if (auto *T = dyn_cast<DefinedRelative>(Config->SEHTable->body()))
- T->setRVA(SEHTable->getRVA());
- if (auto *C = dyn_cast<DefinedAbsolute>(Config->SEHCount->body()))
- C->setVA(SEHTable->getSize() / 4);
+ // 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");
+ replaceBody<DefinedSynthetic>(T, T->body()->getName(), SEHTable);
+ cast<DefinedAbsolute>(C->body())->setVA(SEHTable->getSize() / 4);
}
// Handles /section options to allow users to overwrite
diff --git a/lld/test/COFF/pdb-safeseh.yaml b/lld/test/COFF/pdb-safeseh.yaml
new file mode 100644
index 00000000000..9faa5042924
--- /dev/null
+++ b/lld/test/COFF/pdb-safeseh.yaml
@@ -0,0 +1,85 @@
+# RUN: yaml2obj %s -o %t.obj
+# RUN: lld-link -debug -entry:main -out:%t.exe -pdb:%t.pdb %t.obj
+# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s
+
+# There is an S_GDATA32 symbol record with .secrel32 and .secidx relocations in
+# it in this debug info. This is similar to the relocations in the loadcfg.obj
+# file in the MSVC CRT. We need to make sure that our relocation logic matches
+# MSVC's for these absolute, linker-provided symbols.
+
+# CHECK: Mod 0000 |
+# CHECK-NEXT: - S_GDATA32 [size = 40] `___safe_se_handler_table`
+# CHECK-NEXT: type = 0x0022 (unsigned long), addr = 0003:0000
+# CHECK-NEXT: Mod 0001 | `* Linker *`:
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_GDATA32
+ DataSym:
+ Type: 34
+ DisplayName: ___safe_se_handler_table
+ - !StringTable
+ Strings:
+ Relocations:
+ - VirtualAddress: 20
+ SymbolName: ___safe_se_handler_table
+ Type: IMAGE_REL_I386_SECREL
+ - VirtualAddress: 24
+ SymbolName: ___safe_se_handler_table
+ Type: IMAGE_REL_I386_SECTION
+ - Name: '.text$mn'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 488D0500000000C3
+ Relocations:
+ - VirtualAddress: 3
+ SymbolName: ___safe_se_handler_table
+ Type: IMAGE_REL_I386_REL32
+symbols:
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 372
+ NumberOfRelocations: 6
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '.text$mn'
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 1092178131
+ Number: 0
+ - Name: _main
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: ___safe_se_handler_table
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
+
diff --git a/lld/test/COFF/safeseh.test b/lld/test/COFF/safeseh-diag-feat.test
index ed928a51350..ed928a51350 100644
--- a/lld/test/COFF/safeseh.test
+++ b/lld/test/COFF/safeseh-diag-feat.test
diff --git a/lld/test/COFF/safeseh.s b/lld/test/COFF/safeseh.s
new file mode 100644
index 00000000000..83c15afbf93
--- /dev/null
+++ b/lld/test/COFF/safeseh.s
@@ -0,0 +1,60 @@
+# RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:noref -entry:main
+# RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
+# RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:ref -entry:main
+# RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-GC
+
+# CHECK-NOGC: LoadConfig [
+# CHECK-NOGC: Size: 0x48
+# CHECK-NOGC: SEHandlerTable: 0x401048
+# CHECK-NOGC: SEHandlerCount: 1
+# CHECK-NOGC: ]
+# CHECK-NOGC: SEHTable [
+# CHECK-NOGC-NEXT: 0x402006
+# CHECK-NOGC-NEXT: ]
+
+# CHECK-GC: LoadConfig [
+# CHECK-GC: Size: 0x48
+# CHECK-GC: SEHandlerTable: 0x0
+# CHECK-GC: SEHandlerCount: 0
+# CHECK-GC: ]
+# CHECK-GC-NOT: SEHTable
+
+
+ .def @feat.00;
+ .scl 3;
+ .type 0;
+ .endef
+ .globl @feat.00
+@feat.00 = 1
+
+ .def _main;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,_main
+ .globl _main
+_main:
+ movl $42, %eax
+ ret
+
+# This handler can be GCd, which will make the safeseh table empty, so it should
+# appear null.
+ .def _my_handler;
+ .scl 3;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,_my_handler
+_my_handler:
+ ret
+
+.safeseh _my_handler
+
+
+ .section .rdata,"dr"
+.globl __load_config_used
+__load_config_used:
+ .long 72
+ .fill 60, 1, 0
+ .long ___safe_se_handler_table
+ .long ___safe_se_handler_count
OpenPOWER on IntegriCloud