diff options
Diffstat (limited to 'COFF/Symbols.cpp')
-rw-r--r-- | COFF/Symbols.cpp | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp new file mode 100644 index 000000000000..d732d76cfb06 --- /dev/null +++ b/COFF/Symbols.cpp @@ -0,0 +1,243 @@ +//===- Symbols.cpp --------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm::object; +using llvm::sys::fs::identify_magic; +using llvm::sys::fs::file_magic; + +namespace lld { +namespace coff { + +StringRef SymbolBody::getName() { + // DefinedCOFF names are read lazily for a performance reason. + // Non-external symbol names are never used by the linker except for logging + // or debugging. Their internal references are resolved not by name but by + // symbol index. And because they are not external, no one can refer them by + // name. Object files contain lots of non-external symbols, and creating + // StringRefs for them (which involves lots of strlen() on the string table) + // is a waste of time. + if (Name.empty()) { + auto *D = cast<DefinedCOFF>(this); + D->File->getCOFFObj()->getSymbolName(D->Sym, Name); + } + return Name; +} + +// Returns 1, 0 or -1 if this symbol should take precedence +// over the Other, tie or lose, respectively. +int SymbolBody::compare(SymbolBody *Other) { + Kind LK = kind(), RK = Other->kind(); + + // Normalize so that the smaller kind is on the left. + if (LK > RK) + return -Other->compare(this); + + // First handle comparisons between two different kinds. + if (LK != RK) { + if (RK > LastDefinedKind) { + if (LK == LazyKind && cast<Undefined>(Other)->WeakAlias) + return -1; + + // The LHS is either defined or lazy and so it wins. + assert((LK <= LastDefinedKind || LK == LazyKind) && "Bad kind!"); + return 1; + } + + // Bitcode has special complexities. + if (RK == DefinedBitcodeKind) { + auto *RHS = cast<DefinedBitcode>(Other); + + switch (LK) { + case DefinedCommonKind: + return 1; + + case DefinedRegularKind: + // As an approximation, regular symbols win over bitcode symbols, + // but we definitely have a conflict if the regular symbol is not + // replaceable and neither is the bitcode symbol. We do not + // replicate the rest of the symbol resolution logic here; symbol + // resolution will be done accurately after lowering bitcode symbols + // to regular symbols in addCombinedLTOObject(). + if (cast<DefinedRegular>(this)->isCOMDAT() || RHS->IsReplaceable) + return 1; + + // Fallthrough to the default of a tie otherwise. + default: + return 0; + } + } + + // Either of the object file kind will trump a higher kind. + if (LK <= LastDefinedCOFFKind) + return 1; + + // The remaining kind pairs are ties amongst defined symbols. + return 0; + } + + // Now handle the case where the kinds are the same. + switch (LK) { + case DefinedRegularKind: { + auto *LHS = cast<DefinedRegular>(this); + auto *RHS = cast<DefinedRegular>(Other); + if (LHS->isCOMDAT() && RHS->isCOMDAT()) + return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1; + return 0; + } + + case DefinedCommonKind: { + auto *LHS = cast<DefinedCommon>(this); + auto *RHS = cast<DefinedCommon>(Other); + if (LHS->getSize() == RHS->getSize()) + return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1; + return LHS->getSize() > RHS->getSize() ? 1 : -1; + } + + case DefinedBitcodeKind: { + auto *LHS = cast<DefinedBitcode>(this); + auto *RHS = cast<DefinedBitcode>(Other); + // If both are non-replaceable, we have a tie. + if (!LHS->IsReplaceable && !RHS->IsReplaceable) + return 0; + + // Non-replaceable symbols win, but even two replaceable symboles don't + // tie. If both symbols are replaceable, choice is arbitrary. + if (RHS->IsReplaceable && LHS->IsReplaceable) + return uintptr_t(LHS) < uintptr_t(RHS) ? 1 : -1; + return LHS->IsReplaceable ? -1 : 1; + } + + case LazyKind: { + // Don't tie, pick the earliest. + auto *LHS = cast<Lazy>(this); + auto *RHS = cast<Lazy>(Other); + return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1; + } + + case UndefinedKind: { + auto *LHS = cast<Undefined>(this); + auto *RHS = cast<Undefined>(Other); + // Tie if both undefined symbols have different weak aliases. + if (LHS->WeakAlias && RHS->WeakAlias) { + if (LHS->WeakAlias->getName() != RHS->WeakAlias->getName()) + return 0; + return uintptr_t(LHS) < uintptr_t(RHS) ? 1 : -1; + } + return LHS->WeakAlias ? 1 : -1; + } + + case DefinedLocalImportKind: + case DefinedImportThunkKind: + case DefinedImportDataKind: + case DefinedAbsoluteKind: + case DefinedRelativeKind: + // These all simply tie. + return 0; + } + llvm_unreachable("unknown symbol kind"); +} + +std::string SymbolBody::getDebugName() { + std::string N = getName().str(); + if (auto *D = dyn_cast<DefinedCOFF>(this)) { + N += " "; + N += D->File->getShortName(); + } else if (auto *D = dyn_cast<DefinedBitcode>(this)) { + N += " "; + N += D->File->getShortName(); + } + return N; +} + +uint64_t Defined::getFileOff() { + switch (kind()) { + case DefinedImportDataKind: + return cast<DefinedImportData>(this)->getFileOff(); + case DefinedImportThunkKind: + return cast<DefinedImportThunk>(this)->getFileOff(); + case DefinedLocalImportKind: + return cast<DefinedLocalImport>(this)->getFileOff(); + case DefinedCommonKind: + return cast<DefinedCommon>(this)->getFileOff(); + case DefinedRegularKind: + return cast<DefinedRegular>(this)->getFileOff(); + + case DefinedBitcodeKind: + llvm_unreachable("There is no file offset for a bitcode symbol."); + case DefinedAbsoluteKind: + llvm_unreachable("Cannot get a file offset for an absolute symbol."); + case DefinedRelativeKind: + llvm_unreachable("Cannot get a file offset for a relative symbol."); + case LazyKind: + case UndefinedKind: + llvm_unreachable("Cannot get a file offset for an undefined symbol."); + } + llvm_unreachable("unknown symbol kind"); +} + +COFFSymbolRef DefinedCOFF::getCOFFSymbol() { + size_t SymSize = File->getCOFFObj()->getSymbolTableEntrySize(); + if (SymSize == sizeof(coff_symbol16)) + return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(Sym)); + assert(SymSize == sizeof(coff_symbol32)); + return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym)); +} + +DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S, + uint16_t Machine) + : Defined(DefinedImportThunkKind, Name) { + switch (Machine) { + case AMD64: Data.reset(new ImportThunkChunkX64(S)); return; + case I386: Data.reset(new ImportThunkChunkX86(S)); return; + case ARMNT: Data.reset(new ImportThunkChunkARM(S)); return; + default: llvm_unreachable("unknown machine type"); + } +} + +std::unique_ptr<InputFile> Lazy::getMember() { + MemoryBufferRef MBRef = File->getMember(&Sym); + + // getMember returns an empty buffer if the member was already + // read from the library. + if (MBRef.getBuffer().empty()) + return std::unique_ptr<InputFile>(nullptr); + + file_magic Magic = identify_magic(MBRef.getBuffer()); + if (Magic == file_magic::coff_import_library) + return std::unique_ptr<InputFile>(new ImportFile(MBRef)); + + std::unique_ptr<InputFile> Obj; + if (Magic == file_magic::coff_object) + Obj.reset(new ObjectFile(MBRef)); + else if (Magic == file_magic::bitcode) + Obj.reset(new BitcodeFile(MBRef)); + else + error(Twine(File->getName()) + ": unknown file type"); + + Obj->setParentName(File->getName()); + return Obj; +} + +Defined *Undefined::getWeakAlias() { + // A weak alias may be a weak alias to another symbol, so check recursively. + for (SymbolBody *A = WeakAlias; A; A = cast<Undefined>(A)->WeakAlias) + if (auto *D = dyn_cast<Defined>(A->repl())) + return D; + return nullptr; +} + +} // namespace coff +} // namespace lld |