Rui Ueyama | 4b22fa7 | 2015-06-07 01:15:04 +0000 | [diff] [blame] | 1 | //===- DLL.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 | // This file defines various types of chunks for the DLL import |
| 11 | // descriptor table. They are inherently Windows-specific. |
| 12 | // You need to read Microsoft PE/COFF spec to understand details |
| 13 | // about the data structures. |
| 14 | // |
| 15 | // If you are not particularly interested in linking against Windows |
| 16 | // DLL, you can skip this file, and you should still be able to |
| 17 | // understand the rest of the linker. |
| 18 | // |
| 19 | //===----------------------------------------------------------------------===// |
| 20 | |
| 21 | #include "Chunks.h" |
| 22 | #include "DLL.h" |
| 23 | #include "llvm/ADT/STLExtras.h" |
| 24 | #include "llvm/Object/COFF.h" |
| 25 | #include "llvm/Support/Endian.h" |
| 26 | |
| 27 | using namespace llvm; |
| 28 | using namespace llvm::object; |
| 29 | using namespace llvm::support::endian; |
| 30 | using namespace llvm::COFF; |
| 31 | using llvm::RoundUpToAlignment; |
| 32 | |
Rui Ueyama | 94df713 | 2015-06-07 03:55:28 +0000 | [diff] [blame] | 33 | static const size_t LookupChunkSize = sizeof(uint64_t); |
| 34 | static const size_t DirectoryChunkSize = sizeof(ImportDirectoryTableEntry); |
Rui Ueyama | 4b22fa7 | 2015-06-07 01:15:04 +0000 | [diff] [blame] | 35 | |
| 36 | namespace lld { |
| 37 | namespace coff { |
| 38 | |
| 39 | // A chunk for the import descriptor table. |
| 40 | class HintNameChunk : public Chunk { |
| 41 | public: |
| 42 | HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {} |
| 43 | |
| 44 | size_t getSize() const override { |
| 45 | // Starts with 2 byte Hint field, followed by a null-terminated string, |
| 46 | // ends with 0 or 1 byte padding. |
| 47 | return RoundUpToAlignment(Name.size() + 3, 2); |
| 48 | } |
| 49 | |
| 50 | void writeTo(uint8_t *Buf) override { |
| 51 | write16le(Buf + FileOff, Hint); |
| 52 | memcpy(Buf + FileOff + 2, Name.data(), Name.size()); |
| 53 | } |
| 54 | |
| 55 | private: |
| 56 | StringRef Name; |
| 57 | uint16_t Hint; |
| 58 | }; |
| 59 | |
| 60 | // A chunk for the import descriptor table. |
| 61 | class LookupChunk : public Chunk { |
| 62 | public: |
| 63 | explicit LookupChunk(Chunk *C) : HintName(C) {} |
| 64 | size_t getSize() const override { return LookupChunkSize; } |
| 65 | |
| 66 | void writeTo(uint8_t *Buf) override { |
| 67 | write32le(Buf + FileOff, HintName->getRVA()); |
| 68 | } |
| 69 | |
| 70 | Chunk *HintName; |
| 71 | }; |
| 72 | |
| 73 | // A chunk for the import descriptor table. |
| 74 | // This chunk represent import-by-ordinal symbols. |
| 75 | // See Microsoft PE/COFF spec 7.1. Import Header for details. |
| 76 | class OrdinalOnlyChunk : public Chunk { |
| 77 | public: |
| 78 | explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {} |
| 79 | size_t getSize() const override { return sizeof(uint64_t); } |
| 80 | |
| 81 | void writeTo(uint8_t *Buf) override { |
| 82 | // An import-by-ordinal slot has MSB 1 to indicate that |
| 83 | // this is import-by-ordinal (and not import-by-name). |
| 84 | write64le(Buf + FileOff, (uint64_t(1) << 63) | Ordinal); |
| 85 | } |
| 86 | |
| 87 | uint16_t Ordinal; |
| 88 | }; |
| 89 | |
| 90 | // A chunk for the import descriptor table. |
| 91 | class DirectoryChunk : public Chunk { |
| 92 | public: |
| 93 | explicit DirectoryChunk(Chunk *N) : DLLName(N) {} |
| 94 | size_t getSize() const override { return DirectoryChunkSize; } |
| 95 | |
| 96 | void writeTo(uint8_t *Buf) override { |
| 97 | auto *E = (coff_import_directory_table_entry *)(Buf + FileOff); |
| 98 | E->ImportLookupTableRVA = LookupTab->getRVA(); |
| 99 | E->NameRVA = DLLName->getRVA(); |
| 100 | E->ImportAddressTableRVA = AddressTab->getRVA(); |
| 101 | } |
| 102 | |
| 103 | Chunk *DLLName; |
| 104 | Chunk *LookupTab; |
| 105 | Chunk *AddressTab; |
| 106 | }; |
| 107 | |
| 108 | // A chunk representing null terminator in the import table. |
| 109 | // Contents of this chunk is always null bytes. |
| 110 | class NullChunk : public Chunk { |
| 111 | public: |
| 112 | explicit NullChunk(size_t N) : Size(N) {} |
| 113 | bool hasData() const override { return false; } |
| 114 | size_t getSize() const override { return Size; } |
| 115 | |
| 116 | private: |
| 117 | size_t Size; |
| 118 | }; |
| 119 | |
| 120 | uint64_t IdataContents::getDirSize() { |
| 121 | return Dirs.size() * DirectoryChunkSize; |
| 122 | } |
| 123 | |
| 124 | uint64_t IdataContents::getIATSize() { |
| 125 | return Addresses.size() * LookupChunkSize; |
| 126 | } |
| 127 | |
| 128 | // Returns a list of .idata contents. |
| 129 | // See Microsoft PE/COFF spec 5.4 for details. |
| 130 | std::vector<Chunk *> IdataContents::getChunks() { |
| 131 | create(); |
| 132 | std::vector<Chunk *> V; |
| 133 | // The loader assumes a specific order of data. |
| 134 | // Add each type in the correct order. |
| 135 | for (std::unique_ptr<Chunk> &C : Dirs) |
| 136 | V.push_back(C.get()); |
| 137 | for (std::unique_ptr<Chunk> &C : Lookups) |
| 138 | V.push_back(C.get()); |
| 139 | for (std::unique_ptr<Chunk> &C : Addresses) |
| 140 | V.push_back(C.get()); |
| 141 | for (std::unique_ptr<Chunk> &C : Hints) |
| 142 | V.push_back(C.get()); |
| 143 | for (auto &P : DLLNames) { |
| 144 | std::unique_ptr<Chunk> &C = P.second; |
| 145 | V.push_back(C.get()); |
| 146 | } |
| 147 | return V; |
| 148 | } |
| 149 | |
| 150 | void IdataContents::create() { |
| 151 | // Group DLL-imported symbols by DLL name because that's how |
| 152 | // symbols are layed out in the import descriptor table. |
| 153 | std::map<StringRef, std::vector<DefinedImportData *>> Map; |
| 154 | for (DefinedImportData *Sym : Imports) |
| 155 | Map[Sym->getDLLName()].push_back(Sym); |
| 156 | |
| 157 | // Create .idata contents for each DLL. |
| 158 | for (auto &P : Map) { |
| 159 | StringRef Name = P.first; |
| 160 | std::vector<DefinedImportData *> &Syms = P.second; |
| 161 | |
| 162 | // Sort symbols by name for each group. |
| 163 | std::sort(Syms.begin(), Syms.end(), |
| 164 | [](DefinedImportData *A, DefinedImportData *B) { |
| 165 | return A->getName() < B->getName(); |
| 166 | }); |
| 167 | |
| 168 | // Create lookup and address tables. If they have external names, |
| 169 | // we need to create HintName chunks to store the names. |
| 170 | // If they don't (if they are import-by-ordinals), we store only |
| 171 | // ordinal values to the table. |
| 172 | size_t Base = Lookups.size(); |
| 173 | for (DefinedImportData *S : Syms) { |
| 174 | uint16_t Ord = S->getOrdinal(); |
| 175 | if (S->getExternalName().empty()) { |
| 176 | Lookups.push_back(make_unique<OrdinalOnlyChunk>(Ord)); |
| 177 | Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord)); |
| 178 | continue; |
| 179 | } |
| 180 | auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord); |
| 181 | Lookups.push_back(make_unique<LookupChunk>(C.get())); |
| 182 | Addresses.push_back(make_unique<LookupChunk>(C.get())); |
| 183 | Hints.push_back(std::move(C)); |
| 184 | } |
| 185 | // Terminate with null values. |
| 186 | Lookups.push_back(make_unique<NullChunk>(sizeof(uint64_t))); |
| 187 | Addresses.push_back(make_unique<NullChunk>(sizeof(uint64_t))); |
| 188 | |
| 189 | for (int I = 0, E = Syms.size(); I < E; ++I) |
| 190 | Syms[I]->setLocation(Addresses[Base + I].get()); |
| 191 | |
| 192 | // Create the import table header. |
| 193 | if (!DLLNames.count(Name)) |
| 194 | DLLNames[Name] = make_unique<StringChunk>(Name); |
| 195 | auto Dir = make_unique<DirectoryChunk>(DLLNames[Name].get()); |
| 196 | Dir->LookupTab = Lookups[Base].get(); |
| 197 | Dir->AddressTab = Addresses[Base].get(); |
| 198 | Dirs.push_back(std::move(Dir)); |
| 199 | } |
| 200 | // Add null terminator. |
| 201 | Dirs.push_back(make_unique<NullChunk>(DirectoryChunkSize)); |
| 202 | } |
| 203 | |
| 204 | } // namespace coff |
| 205 | } // namespace lld |