| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 1 | //===- InputFiles.cpp -----------------------------------------------------===// |
| 2 | // |
| 3 | // The LLVM Linker |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
| 10 | #include "InputFiles.h" |
| 11 | #include "Chunks.h" |
| Rafael Espindola | 192e1fa | 2015-08-06 15:08:23 +0000 | [diff] [blame] | 12 | #include "Error.h" |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 13 | #include "Symbols.h" |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 14 | #include "llvm/ADT/STLExtras.h" |
| 15 | |
| Michael J. Spencer | 1b348a6 | 2015-09-04 22:28:10 +0000 | [diff] [blame] | 16 | using namespace llvm; |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 17 | using namespace llvm::ELF; |
| Rafael Espindola | f98d6d8 | 2015-09-03 20:03:54 +0000 | [diff] [blame] | 18 | using namespace llvm::object; |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 19 | |
| 20 | using namespace lld; |
| 21 | using namespace lld::elf2; |
| 22 | |
| Rafael Espindola | f98d6d8 | 2015-09-03 20:03:54 +0000 | [diff] [blame] | 23 | template <class ELFT> static uint16_t getEMachine(const ELFFileBase &B) { |
| 24 | bool IsShared = isa<SharedFileBase>(B); |
| 25 | if (IsShared) |
| 26 | return cast<SharedFile<ELFT>>(B).getEMachine(); |
| 27 | return cast<ObjectFile<ELFT>>(B).getEMachine(); |
| Rafael Espindola | 3c9cb4b | 2015-08-05 12:03:34 +0000 | [diff] [blame] | 28 | } |
| 29 | |
| Rafael Espindola | f98d6d8 | 2015-09-03 20:03:54 +0000 | [diff] [blame] | 30 | static uint16_t getEMachine(const ELFFileBase &B) { |
| 31 | ELFKind K = B.getELFKind(); |
| 32 | switch (K) { |
| 33 | case ELF32BEKind: |
| 34 | return getEMachine<ELF32BE>(B); |
| 35 | case ELF32LEKind: |
| 36 | return getEMachine<ELF32LE>(B); |
| 37 | case ELF64BEKind: |
| 38 | return getEMachine<ELF64BE>(B); |
| 39 | case ELF64LEKind: |
| 40 | return getEMachine<ELF64LE>(B); |
| 41 | } |
| Rafael Espindola | 55eed7ef | 2015-09-03 22:25:11 +0000 | [diff] [blame] | 42 | llvm_unreachable("Invalid kind"); |
| Rafael Espindola | f98d6d8 | 2015-09-03 20:03:54 +0000 | [diff] [blame] | 43 | } |
| 44 | |
| 45 | bool ELFFileBase::isCompatibleWith(const ELFFileBase &Other) const { |
| 46 | return getELFKind() == Other.getELFKind() && |
| 47 | getEMachine(*this) == getEMachine(Other); |
| 48 | } |
| 49 | |
| 50 | template <class ELFT> void ELFData<ELFT>::openELF(MemoryBufferRef MB) { |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 51 | // Parse a memory buffer as a ELF file. |
| 52 | std::error_code EC; |
| 53 | ELFObj = llvm::make_unique<ELFFile<ELFT>>(MB.getBuffer(), EC); |
| 54 | error(EC); |
| Rafael Espindola | f98d6d8 | 2015-09-03 20:03:54 +0000 | [diff] [blame] | 55 | } |
| 56 | |
| 57 | template <class ELFT> void elf2::ObjectFile<ELFT>::parse() { |
| 58 | this->openELF(MB); |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 59 | |
| 60 | // Read section and symbol tables. |
| 61 | initializeChunks(); |
| 62 | initializeSymbols(); |
| 63 | } |
| 64 | |
| 65 | template <class ELFT> void elf2::ObjectFile<ELFT>::initializeChunks() { |
| Rafael Espindola | f98d6d8 | 2015-09-03 20:03:54 +0000 | [diff] [blame] | 66 | uint64_t Size = this->ELFObj->getNumSections(); |
| Rafael Espindola | 832b93f | 2015-08-24 20:06:32 +0000 | [diff] [blame] | 67 | Chunks.resize(Size); |
| 68 | unsigned I = 0; |
| Rafael Espindola | f98d6d8 | 2015-09-03 20:03:54 +0000 | [diff] [blame] | 69 | for (const Elf_Shdr &Sec : this->ELFObj->sections()) { |
| Rafael Espindola | cde2513 | 2015-08-13 14:45:44 +0000 | [diff] [blame] | 70 | switch (Sec.sh_type) { |
| 71 | case SHT_SYMTAB: |
| Rafael Espindola | d8340da | 2015-08-10 15:12:17 +0000 | [diff] [blame] | 72 | Symtab = &Sec; |
| Rafael Espindola | cde2513 | 2015-08-13 14:45:44 +0000 | [diff] [blame] | 73 | break; |
| Rafael Espindola | 2034822 | 2015-08-24 21:43:25 +0000 | [diff] [blame] | 74 | case SHT_SYMTAB_SHNDX: { |
| Rafael Espindola | f98d6d8 | 2015-09-03 20:03:54 +0000 | [diff] [blame] | 75 | ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable = |
| 76 | this->ELFObj->getSHNDXTable(Sec); |
| Rafael Espindola | 2034822 | 2015-08-24 21:43:25 +0000 | [diff] [blame] | 77 | error(ErrorOrTable); |
| 78 | SymtabSHNDX = *ErrorOrTable; |
| 79 | break; |
| 80 | } |
| Rafael Espindola | cde2513 | 2015-08-13 14:45:44 +0000 | [diff] [blame] | 81 | case SHT_STRTAB: |
| 82 | case SHT_NULL: |
| Rafael Espindola | cde2513 | 2015-08-13 14:45:44 +0000 | [diff] [blame] | 83 | break; |
| Michael J. Spencer | 67bc8d6 | 2015-08-27 23:15:56 +0000 | [diff] [blame] | 84 | case SHT_RELA: |
| 85 | case SHT_REL: { |
| 86 | uint32_t RelocatedSectionIndex = Sec.sh_info; |
| 87 | if (RelocatedSectionIndex >= Size) |
| 88 | error("Invalid relocated section index"); |
| 89 | SectionChunk<ELFT> *RelocatedSection = Chunks[RelocatedSectionIndex]; |
| 90 | if (!RelocatedSection) |
| 91 | error("Unsupported relocation reference"); |
| 92 | RelocatedSection->RelocSections.push_back(&Sec); |
| 93 | break; |
| 94 | } |
| Rafael Espindola | cde2513 | 2015-08-13 14:45:44 +0000 | [diff] [blame] | 95 | default: |
| Michael J. Spencer | 67bc8d6 | 2015-08-27 23:15:56 +0000 | [diff] [blame] | 96 | Chunks[I] = new (Alloc) SectionChunk<ELFT>(this, &Sec); |
| Rafael Espindola | cde2513 | 2015-08-13 14:45:44 +0000 | [diff] [blame] | 97 | break; |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 98 | } |
| Rafael Espindola | 832b93f | 2015-08-24 20:06:32 +0000 | [diff] [blame] | 99 | ++I; |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 100 | } |
| 101 | } |
| 102 | |
| 103 | template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() { |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 104 | ErrorOr<StringRef> StringTableOrErr = |
| Rafael Espindola | f98d6d8 | 2015-09-03 20:03:54 +0000 | [diff] [blame] | 105 | this->ELFObj->getStringTableForSymtab(*Symtab); |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 106 | error(StringTableOrErr.getError()); |
| 107 | StringRef StringTable = *StringTableOrErr; |
| 108 | |
| Rafael Espindola | f98d6d8 | 2015-09-03 20:03:54 +0000 | [diff] [blame] | 109 | Elf_Sym_Range Syms = this->ELFObj->symbols(Symtab); |
| Reid Kleckner | f7b85e0 | 2015-08-11 20:06:51 +0000 | [diff] [blame] | 110 | uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); |
| Rafael Espindola | 7c38818 | 2015-08-11 16:30:34 +0000 | [diff] [blame] | 111 | uint32_t FirstNonLocal = Symtab->sh_info; |
| 112 | if (FirstNonLocal > NumSymbols) |
| 113 | error("Invalid sh_info in symbol table"); |
| 114 | Syms = llvm::make_range(Syms.begin() + FirstNonLocal, Syms.end()); |
| Davide Italiano | 34812ba | 2015-09-03 20:25:54 +0000 | [diff] [blame] | 115 | SymbolBodies.reserve(NumSymbols - FirstNonLocal); |
| Rafael Espindola | 3031851 | 2015-08-04 14:00:56 +0000 | [diff] [blame] | 116 | for (const Elf_Sym &Sym : Syms) |
| 117 | SymbolBodies.push_back(createSymbolBody(StringTable, &Sym)); |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | template <class ELFT> |
| 121 | SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable, |
| 122 | const Elf_Sym *Sym) { |
| 123 | ErrorOr<StringRef> NameOrErr = Sym->getName(StringTable); |
| 124 | error(NameOrErr.getError()); |
| 125 | StringRef Name = *NameOrErr; |
| Rafael Espindola | 2034822 | 2015-08-24 21:43:25 +0000 | [diff] [blame] | 126 | |
| 127 | uint32_t SecIndex = Sym->st_shndx; |
| Rafael Espindola | 51d4690 | 2015-08-28 21:26:51 +0000 | [diff] [blame] | 128 | switch (SecIndex) { |
| 129 | case SHN_ABS: |
| Rafael Espindola | 0e0c190 | 2015-08-27 12:40:06 +0000 | [diff] [blame] | 130 | return new (Alloc) DefinedAbsolute<ELFT>(Name, *Sym); |
| Rafael Espindola | 51d4690 | 2015-08-28 21:26:51 +0000 | [diff] [blame] | 131 | case SHN_UNDEF: |
| 132 | return new (Alloc) Undefined<ELFT>(Name, *Sym); |
| 133 | case SHN_COMMON: |
| 134 | return new (Alloc) DefinedCommon<ELFT>(Name, *Sym); |
| 135 | case SHN_XINDEX: |
| Rafael Espindola | f98d6d8 | 2015-09-03 20:03:54 +0000 | [diff] [blame] | 136 | SecIndex = |
| 137 | this->ELFObj->getExtendedSymbolTableIndex(Sym, Symtab, SymtabSHNDX); |
| Rafael Espindola | 51d4690 | 2015-08-28 21:26:51 +0000 | [diff] [blame] | 138 | break; |
| 139 | } |
| Rafael Espindola | 2034822 | 2015-08-24 21:43:25 +0000 | [diff] [blame] | 140 | |
| Rafael Espindola | 5cd113d | 2015-08-24 22:00:25 +0000 | [diff] [blame] | 141 | if (SecIndex >= Chunks.size() || |
| 142 | (SecIndex != 0 && !Chunks[SecIndex])) |
| 143 | error("Invalid section index"); |
| 144 | |
| Rafael Espindola | b13df65 | 2015-08-11 17:33:02 +0000 | [diff] [blame] | 145 | switch (Sym->getBinding()) { |
| 146 | default: |
| 147 | error("unexpected binding"); |
| 148 | case STB_GLOBAL: |
| Rafael Espindola | 3a63f3f | 2015-08-28 20:19:34 +0000 | [diff] [blame] | 149 | case STB_WEAK: |
| Rafael Espindola | 832b93f | 2015-08-24 20:06:32 +0000 | [diff] [blame] | 150 | return new (Alloc) DefinedRegular<ELFT>(Name, *Sym, *Chunks[SecIndex]); |
| Rafael Espindola | b13df65 | 2015-08-11 17:33:02 +0000 | [diff] [blame] | 151 | } |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 152 | } |
| 153 | |
| Michael J. Spencer | 1b348a6 | 2015-09-04 22:28:10 +0000 | [diff] [blame] | 154 | void ArchiveFile::parse() { |
| 155 | auto ArchiveOrErr = Archive::create(MB); |
| 156 | error(ArchiveOrErr, "Failed to parse archive"); |
| 157 | File = std::move(*ArchiveOrErr); |
| 158 | |
| 159 | // Allocate a buffer for Lazy objects. |
| 160 | size_t NumSyms = File->getNumberOfSymbols(); |
| 161 | LazySymbols.reserve(NumSyms); |
| 162 | |
| 163 | // Read the symbol table to construct Lazy objects. |
| 164 | for (const Archive::Symbol &Sym : File->symbols()) |
| 165 | LazySymbols.emplace_back(this, Sym); |
| 166 | } |
| 167 | |
| 168 | // Returns a buffer pointing to a member file containing a given symbol. |
| 169 | MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) { |
| 170 | ErrorOr<Archive::child_iterator> ItOrErr = Sym->getMember(); |
| 171 | error(ItOrErr, |
| 172 | Twine("Could not get the member for symbol ") + Sym->getName()); |
| 173 | Archive::child_iterator It = *ItOrErr; |
| 174 | |
| 175 | if (!Seen.insert(It->getChildOffset()).second) { |
| 176 | return MemoryBufferRef(); |
| 177 | } |
| 178 | ErrorOr<MemoryBufferRef> Ret = It->getMemoryBufferRef(); |
| 179 | error(Ret, Twine("Could not get the buffer for the member defining symbol ") + |
| 180 | Sym->getName()); |
| 181 | return *Ret; |
| 182 | } |
| 183 | |
| Rafael Espindola | f98d6d8 | 2015-09-03 20:03:54 +0000 | [diff] [blame] | 184 | template <class ELFT> void SharedFile<ELFT>::parse() { this->openELF(MB); } |
| 185 | |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 186 | namespace lld { |
| 187 | namespace elf2 { |
| 188 | template class elf2::ObjectFile<llvm::object::ELF32LE>; |
| 189 | template class elf2::ObjectFile<llvm::object::ELF32BE>; |
| 190 | template class elf2::ObjectFile<llvm::object::ELF64LE>; |
| 191 | template class elf2::ObjectFile<llvm::object::ELF64BE>; |
| Rafael Espindola | f98d6d8 | 2015-09-03 20:03:54 +0000 | [diff] [blame] | 192 | |
| 193 | template class elf2::SharedFile<llvm::object::ELF32LE>; |
| 194 | template class elf2::SharedFile<llvm::object::ELF32BE>; |
| 195 | template class elf2::SharedFile<llvm::object::ELF64LE>; |
| 196 | template class elf2::SharedFile<llvm::object::ELF64BE>; |
| Michael J. Spencer | 84487f1 | 2015-07-24 21:03:07 +0000 | [diff] [blame] | 197 | } |
| 198 | } |