Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/COFF/Driver.cpp @@ -1026,10 +1026,10 @@ 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. Index: lld/trunk/COFF/SymbolTable.h =================================================================== --- lld/trunk/COFF/SymbolTable.h +++ lld/trunk/COFF/SymbolTable.h @@ -85,7 +85,7 @@ // 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); Index: lld/trunk/COFF/SymbolTable.cpp =================================================================== --- lld/trunk/COFF/SymbolTable.cpp +++ lld/trunk/COFF/SymbolTable.cpp @@ -219,13 +219,13 @@ 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(S->body()) || isa(S->body())) - replaceBody(S, N, VA); + replaceBody(S, N, C); else if (!isa(S->body())) reportDuplicate(S, nullptr); return S; Index: lld/trunk/COFF/Symbols.h =================================================================== --- lld/trunk/COFF/Symbols.h +++ lld/trunk/COFF/Symbols.h @@ -50,13 +50,13 @@ DefinedImportThunkKind, DefinedImportDataKind, DefinedAbsoluteKind, - DefinedRelativeKind, + DefinedSyntheticKind, UndefinedKind, LazyKind, LastDefinedCOFFKind = DefinedCommonKind, - LastDefinedKind = DefinedRelativeKind, + LastDefinedKind = DefinedSyntheticKind, }; Kind kind() const { return static_cast(SymbolKind); } @@ -112,11 +112,11 @@ // 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 @@ bool isCOMDAT() { return IsCOMDAT; } SectionChunk *getChunk() { return *Data; } uint32_t getValue() { return Sym->Value; } + uint32_t getSecrel(); private: SectionChunk **Data; @@ -221,24 +222,25 @@ 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 @@ switch (kind()) { case DefinedAbsoluteKind: return cast(this)->getRVA(); - case DefinedRelativeKind: - return cast(this)->getRVA(); + case DefinedSyntheticKind: + return cast(this)->getRVA(); case DefinedImportDataKind: return cast(this)->getRVA(); case DefinedImportThunkKind: @@ -391,7 +393,7 @@ // 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; Index: lld/trunk/COFF/Writer.cpp =================================================================== --- lld/trunk/COFF/Writer.cpp +++ lld/trunk/COFF/Writer.cpp @@ -210,17 +210,36 @@ } } -uint64_t Defined::getSecrel() { - if (auto *D = dyn_cast(this)) - return getRVA() - D->getChunk()->getOutputSection()->getRVA(); +uint32_t Defined::getSecrel() { + assert(this); + switch (kind()) { + case DefinedRegularKind: + return cast(this)->getSecrel(); + case DefinedSyntheticKind: + return cast(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(this)) return D->getChunk()->getOutputSection()->SectionIndex; if (isa(this)) return DefinedAbsolute::OutputSectionIndex; + if (auto *D = dyn_cast(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 @@ for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { if (!File->SEHCompat) return; - for (SymbolBody *B : File->SEHandlers) - Handlers.insert(cast(B)); + for (SymbolBody *B : File->SEHandlers) { + // Make sure the handler is still live. Assume all handlers are regular + // symbols. + auto *D = dyn_cast(B); + if (D && D->getChunk()->isLive()) + Handlers.insert(D); + } } - SEHTable = make(Handlers); - RData->addChunk(SEHTable); + if (!Handlers.empty()) { + SEHTable = make(Handlers); + RData->addChunk(SEHTable); + } } // Create .idata section for the DLL-imported symbol table. @@ -445,7 +471,7 @@ Optional Writer::createSymbol(Defined *Def) { // Relative symbols are unrepresentable in a COFF symbol table. - if (isa(Def)) + if (isa(Def)) return None; if (auto *D = dyn_cast(Def)) { @@ -758,10 +784,13 @@ void Writer::fixSafeSEHSymbols() { if (!SEHTable) return; - if (auto *T = dyn_cast(Config->SEHTable->body())) - T->setRVA(SEHTable->getRVA()); - if (auto *C = dyn_cast(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(T, T->body()->getName(), SEHTable); + cast(C->body())->setVA(SEHTable->getSize() / 4); } // Handles /section options to allow users to overwrite Index: lld/trunk/test/COFF/pdb-safeseh.yaml =================================================================== --- lld/trunk/test/COFF/pdb-safeseh.yaml +++ lld/trunk/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 +... + Index: lld/trunk/test/COFF/safeseh-diag-feat.test =================================================================== --- lld/trunk/test/COFF/safeseh-diag-feat.test +++ lld/trunk/test/COFF/safeseh-diag-feat.test @@ -0,0 +1,51 @@ +# RUN: sed s/FEAT_VALUE/1/ %s | yaml2obj > %t.obj +# RUN: lld-link /out:%t.exe /subsystem:console /entry:main /safeseh %t.obj + +# RUN: sed s/FEAT_VALUE/0/ %s | yaml2obj > %t.obj +# RUN: not lld-link /out:%t.exe /subsystem:console /entry:main \ +# RUN: /safeseh %t.obj >& %t.log +# RUN: FileCheck %s < %t.log + +# CHECK: /safeseh: {{.*}} is not compatible with SEH + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 0000000000000000 +symbols: + - Name: '@comp.id' + Value: 14766605 + SectionNumber: 65535 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: '@feat.00' + Value: FEAT_VALUE + SectionNumber: 65535 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: _main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: lld/trunk/test/COFF/safeseh.s =================================================================== --- lld/trunk/test/COFF/safeseh.s +++ lld/trunk/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 Index: lld/trunk/test/COFF/safeseh.test =================================================================== --- lld/trunk/test/COFF/safeseh.test +++ lld/trunk/test/COFF/safeseh.test @@ -1,51 +0,0 @@ -# RUN: sed s/FEAT_VALUE/1/ %s | yaml2obj > %t.obj -# RUN: lld-link /out:%t.exe /subsystem:console /entry:main /safeseh %t.obj - -# RUN: sed s/FEAT_VALUE/0/ %s | yaml2obj > %t.obj -# RUN: not lld-link /out:%t.exe /subsystem:console /entry:main \ -# RUN: /safeseh %t.obj >& %t.log -# RUN: FileCheck %s < %t.log - -# CHECK: /safeseh: {{.*}} is not compatible with SEH - ---- !COFF -header: - Machine: IMAGE_FILE_MACHINE_I386 - Characteristics: [ ] -sections: - - Name: .text - Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] - Alignment: 1 - SectionData: 0000000000000000 -symbols: - - Name: '@comp.id' - Value: 14766605 - SectionNumber: 65535 - SimpleType: IMAGE_SYM_TYPE_NULL - ComplexType: IMAGE_SYM_DTYPE_NULL - StorageClass: IMAGE_SYM_CLASS_STATIC - - Name: '@feat.00' - Value: FEAT_VALUE - SectionNumber: 65535 - SimpleType: IMAGE_SYM_TYPE_NULL - ComplexType: IMAGE_SYM_DTYPE_NULL - StorageClass: IMAGE_SYM_CLASS_STATIC - - Name: .text - Value: 0 - SectionNumber: 1 - SimpleType: IMAGE_SYM_TYPE_NULL - ComplexType: IMAGE_SYM_DTYPE_NULL - StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: - Length: 8 - NumberOfRelocations: 0 - NumberOfLinenumbers: 0 - CheckSum: 0 - Number: 0 - - Name: _main - Value: 0 - SectionNumber: 1 - SimpleType: IMAGE_SYM_TYPE_NULL - ComplexType: IMAGE_SYM_DTYPE_FUNCTION - StorageClass: IMAGE_SYM_CLASS_EXTERNAL -...