aboutsummaryrefslogtreecommitdiffstats
path: root/COFF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-07-01 13:24:45 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-07-01 13:24:45 +0000
commit0317860f00ca8e821989c92c8a6cc461fd5f2009 (patch)
treeba31f275eb4dfa527c0cd564ba6c5016e2318b16 /COFF
parent4ea16835ba66f2240d050ffcaee44cee6c97cab9 (diff)
downloadsrc-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.cpp95
-rw-r--r--COFF/Chunks.h9
-rw-r--r--COFF/Driver.h1
-rw-r--r--COFF/MarkLive.cpp7
-rw-r--r--COFF/Symbols.h51
-rw-r--r--COFF/Writer.cpp50
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