diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-07-01 13:24:45 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-07-01 13:24:45 +0000 |
commit | 0317860f00ca8e821989c92c8a6cc461fd5f2009 (patch) | |
tree | ba31f275eb4dfa527c0cd564ba6c5016e2318b16 /COFF | |
parent | 4ea16835ba66f2240d050ffcaee44cee6c97cab9 (diff) | |
download | src-0317860f00ca8e821989c92c8a6cc461fd5f2009.tar.gz src-0317860f00ca8e821989c92c8a6cc461fd5f2009.zip |
Vendor import of lld trunk r306956:vendor/lld/lld-trunk-r306956
Notes
Notes:
svn path=/vendor/lld/dist/; revision=320541
svn path=/vendor/lld/lld-trunk-r306956/; revision=320542; tag=vendor/lld/lld-trunk-r306956
Diffstat (limited to 'COFF')
-rw-r--r-- | COFF/Chunks.cpp | 95 | ||||
-rw-r--r-- | COFF/Chunks.h | 9 | ||||
-rw-r--r-- | COFF/Driver.h | 1 | ||||
-rw-r--r-- | COFF/MarkLive.cpp | 7 | ||||
-rw-r--r-- | COFF/Symbols.h | 51 | ||||
-rw-r--r-- | COFF/Writer.cpp | 50 |
6 files changed, 109 insertions, 104 deletions
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp index 56124acaf9a1..9b642dcaf137 100644 --- a/COFF/Chunks.cpp +++ b/COFF/Chunks.cpp @@ -11,6 +11,7 @@ #include "Error.h" #include "InputFiles.h" #include "Symbols.h" +#include "Writer.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/COFF.h" @@ -52,18 +53,27 @@ static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } -static void applySecRel(const SectionChunk *Sec, uint8_t *Off, Defined *Sym) { - // Don't apply section relative relocations to absolute symbols in codeview - // debug info sections. MSVC does not treat such relocations as fatal errors, - // and they can be found in the standard library for linker-provided symbols - // like __guard_fids_table and __safe_se_handler_table. - if (!(isa<DefinedAbsolute>(Sym) && Sec->isCodeView())) - add32(Off, Sym->getSecrel()); +static void applySecRel(const SectionChunk *Sec, uint8_t *Off, + OutputSection *OS, uint64_t S) { + if (!OS) { + if (Sec->isCodeView()) + return; + fatal("SECREL relocation cannot be applied to absolute symbols"); + } + uint64_t SecRel = S - OS->getRVA(); + assert(SecRel < INT32_MAX && "overflow in SECREL relocation"); + add32(Off, SecRel); +} + +static void applySecIdx(uint8_t *Off, OutputSection *OS) { + // If we have no output section, this must be an absolute symbol. Use the + // sentinel absolute symbol section index. + uint16_t SecIdx = OS ? OS->SectionIndex : DefinedAbsolute::OutputSectionIndex; + add16(Off, SecIdx); } -void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, - uint64_t P) const { - uint64_t S = Sym->getRVA(); +void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, + uint64_t S, uint64_t P) const { switch (Type) { case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break; case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break; @@ -74,23 +84,22 @@ void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break; case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break; case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break; - case IMAGE_REL_AMD64_SECTION: add16(Off, Sym->getSectionIndex()); break; - case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, Sym); break; + case IMAGE_REL_AMD64_SECTION: applySecIdx(Off, OS); break; + case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break; default: fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); } } -void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, - uint64_t P) const { - uint64_t S = Sym->getRVA(); +void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, + uint64_t S, uint64_t P) const { switch (Type) { case IMAGE_REL_I386_ABSOLUTE: break; case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; - case IMAGE_REL_I386_SECTION: add16(Off, Sym->getSectionIndex()); break; - case IMAGE_REL_I386_SECREL: applySecRel(this, Off, Sym); break; + case IMAGE_REL_I386_SECTION: applySecIdx(Off, OS); break; + case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break; default: fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); } @@ -137,20 +146,21 @@ static void applyBranch24T(uint8_t *Off, int32_t V) { write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); } -void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, - uint64_t P) const { - uint64_t S = Sym->getRVA(); +void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, + uint64_t S, uint64_t P) const { // Pointer to thumb code must have the LSB set. - if (Sym->isExecutable()) - S |= 1; + uint64_t SX = S; + if (OS && (OS->getPermissions() & IMAGE_SCN_MEM_EXECUTE)) + SX |= 1; switch (Type) { - case IMAGE_REL_ARM_ADDR32: add32(Off, S + Config->ImageBase); break; - case IMAGE_REL_ARM_ADDR32NB: add32(Off, S); break; - case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, S + Config->ImageBase); break; - case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, S - P - 4); break; - case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, S - P - 4); break; - case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, S - P - 4); break; - case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, Sym); break; + case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break; + case IMAGE_REL_ARM_ADDR32NB: add32(Off, SX); break; + case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, SX + Config->ImageBase); break; + case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, SX - P - 4); break; + case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, SX - P - 4); break; + case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, SX - P - 4); break; + case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break; + case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break; default: fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); } @@ -166,18 +176,39 @@ void SectionChunk::writeTo(uint8_t *Buf) const { // Apply relocations. for (const coff_relocation &Rel : Relocs) { uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; + + // Get the output section of the symbol for this relocation. The output + // section is needed to compute SECREL and SECTION relocations used in debug + // info. SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex); Defined *Sym = cast<Defined>(Body); + Chunk *C = Sym->getChunk(); + OutputSection *OS = C ? C->getOutputSection() : nullptr; + + // Only absolute and __ImageBase symbols lack an output section. For any + // other symbol, this indicates that the chunk was discarded. Normally + // relocations against discarded sections are an error. However, debug info + // sections are not GC roots and can end up with these kinds of relocations. + // Skip these relocations. + if (!OS && !isa<DefinedAbsolute>(Sym) && !isa<DefinedSynthetic>(Sym)) { + if (isCodeView()) + continue; + fatal("relocation against symbol in discarded section: " + + Sym->getName()); + } + uint64_t S = Sym->getRVA(); + + // Compute the RVA of the relocation for relative relocations. uint64_t P = RVA + Rel.VirtualAddress; switch (Config->Machine) { case AMD64: - applyRelX64(Off, Rel.Type, Sym, P); + applyRelX64(Off, Rel.Type, OS, S, P); break; case I386: - applyRelX86(Off, Rel.Type, Sym, P); + applyRelX86(Off, Rel.Type, OS, S, P); break; case ARMNT: - applyRelARM(Off, Rel.Type, Sym, P); + applyRelARM(Off, Rel.Type, OS, S, P); break; default: llvm_unreachable("unknown machine type"); diff --git a/COFF/Chunks.h b/COFF/Chunks.h index 54fffc5f6d08..6e1bf94da1a5 100644 --- a/COFF/Chunks.h +++ b/COFF/Chunks.h @@ -145,9 +145,12 @@ public: StringRef getSectionName() const override { return SectionName; } void getBaserels(std::vector<Baserel> *Res) override; bool isCOMDAT() const; - void applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const; - void applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const; - void applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const; + void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; + void applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; + void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; // Called if the garbage collector decides to not include this chunk // in a final output. It's supposed to print out a log message to stdout. diff --git a/COFF/Driver.h b/COFF/Driver.h index 2b5d1e7ae28b..6879be2eb0c7 100644 --- a/COFF/Driver.h +++ b/COFF/Driver.h @@ -34,7 +34,6 @@ extern LinkerDriver *Driver; using llvm::COFF::MachineTypes; using llvm::COFF::WindowsSubsystem; using llvm::Optional; -class InputFile; // Implemented in MarkLive.cpp. void markLive(const std::vector<Chunk *> &Chunks); diff --git a/COFF/MarkLive.cpp b/COFF/MarkLive.cpp index 25e5cc350673..a2756e5c89e0 100644 --- a/COFF/MarkLive.cpp +++ b/COFF/MarkLive.cpp @@ -52,6 +52,13 @@ void markLive(const std::vector<Chunk *> &Chunks) { while (!Worklist.empty()) { SectionChunk *SC = Worklist.pop_back_val(); + + // If this section was discarded, there are relocations referring to + // discarded sections. Ignore these sections to avoid crashing. They will be + // diagnosed during relocation processing. + if (SC->isDiscarded()) + continue; + assert(SC->isLive() && "We mark as live when pushing onto the worklist!"); // Mark all symbols listed in the relocation table for this section. diff --git a/COFF/Symbols.h b/COFF/Symbols.h index 8c1390c45876..a12ae1c01e07 100644 --- a/COFF/Symbols.h +++ b/COFF/Symbols.h @@ -110,17 +110,9 @@ public: // writer sets and uses RVAs. uint64_t getRVA(); - // Returns the RVA relative to the beginning of the output section. - // Used to implement SECREL relocation type. - uint32_t getSecrel(); - - // Returns the output section index. - // Used to implement SECTION relocation type. - uint16_t getSectionIndex(); - - // Returns true if this symbol points to an executable (e.g. .text) section. - // Used to implement ARM relocations. - bool isExecutable(); + // Returns the chunk containing this symbol. Absolute symbols and __ImageBase + // do not have chunks, so this may return null. + Chunk *getChunk(); }; // Symbols defined via a COFF object file or bitcode file. For COFF files, this @@ -167,7 +159,6 @@ public: bool isCOMDAT() { return IsCOMDAT; } SectionChunk *getChunk() { return *Data; } uint32_t getValue() { return Sym->Value; } - uint32_t getSecrel(); private: SectionChunk **Data; @@ -187,8 +178,7 @@ public: } uint64_t getRVA() { return Data->getRVA(); } - uint32_t getSecrel() { return Data->OutputSectionOff; } - uint16_t getSectionIndex(); + Chunk *getChunk() { return Data; } private: friend SymbolTable; @@ -219,6 +209,7 @@ public: // against absolute symbols resolve to this 16 bit number, and it is the // largest valid section index plus one. This is written by the Writer. static uint16_t OutputSectionIndex; + uint16_t getSecIdx() { return OutputSectionIndex; } private: uint64_t VA; @@ -237,9 +228,8 @@ public: // 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; } + uint32_t getRVA() { return C ? C->getRVA() : 0; } + Chunk *getChunk() { return C; } private: Chunk *C; @@ -304,9 +294,11 @@ public: } uint64_t getRVA() { return File->Location->getRVA(); } + Chunk *getChunk() { return File->Location; } + void setLocation(Chunk *AddressTable) { File->Location = AddressTable; } + StringRef getDLLName() { return File->DLLName; } StringRef getExternalName() { return File->ExternalName; } - void setLocation(Chunk *AddressTable) { File->Location = AddressTable; } uint16_t getOrdinal() { return File->Hdr->OrdinalHint; } ImportFile *File; @@ -378,6 +370,29 @@ inline uint64_t Defined::getRVA() { llvm_unreachable("unknown symbol kind"); } +inline Chunk *Defined::getChunk() { + switch (kind()) { + case DefinedRegularKind: + return cast<DefinedRegular>(this)->getChunk(); + case DefinedAbsoluteKind: + return nullptr; + case DefinedSyntheticKind: + return cast<DefinedSynthetic>(this)->getChunk(); + case DefinedImportDataKind: + return cast<DefinedImportData>(this)->getChunk(); + case DefinedImportThunkKind: + return cast<DefinedImportThunk>(this)->getChunk(); + case DefinedLocalImportKind: + return cast<DefinedLocalImport>(this)->getChunk(); + case DefinedCommonKind: + return cast<DefinedCommon>(this)->getChunk(); + case LazyKind: + case UndefinedKind: + llvm_unreachable("Cannot get the chunk of an undefined symbol."); + } + llvm_unreachable("unknown symbol kind"); +} + // A real symbol object, SymbolBody, is usually stored within a Symbol. There's // always one Symbol for each symbol name. The resolver updates the SymbolBody // stored in the Body field of this object as it resolves symbols. Symbol also diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp index d32577b361fa..4cf718a48d8b 100644 --- a/COFF/Writer.cpp +++ b/COFF/Writer.cpp @@ -120,7 +120,6 @@ private: void writeSections(); void sortExceptionTable(); void writeBuildId(); - void applyRelocations(); llvm::Optional<coff_symbol16> createSymbol(Defined *D); size_t addEntryToStringTable(StringRef Str); @@ -210,55 +209,6 @@ void OutputSection::writeHeaderTo(uint8_t *Buf) { } } -uint32_t Defined::getSecrel() { - assert(this); - switch (kind()) { - case DefinedRegularKind: - return cast<DefinedRegular>(this)->getSecrel(); - case DefinedCommonKind: - return cast<DefinedCommon>(this)->getSecrel(); - case DefinedSyntheticKind: - return cast<DefinedSynthetic>(this)->getSecrel(); - default: - break; - } - fatal("SECREL relocation points to a non-regular symbol: " + toString(*this)); -} - -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<DefinedCommon>(this)) - return D->getSectionIndex(); - 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)); -} - -uint16_t DefinedCommon::getSectionIndex() { - return Data->getOutputSection()->SectionIndex; -} - -bool Defined::isExecutable() { - const auto X = IMAGE_SCN_MEM_EXECUTE; - if (auto *D = dyn_cast<DefinedRegular>(this)) - return D->getChunk()->getOutputSection()->getPermissions() & X; - return isa<DefinedImportThunk>(this); -} - } // namespace coff } // namespace lld |