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 33 static const size_t LookupChunkSize = sizeof(uint64_t); 34 static const size_t DirectoryChunkSize = sizeof(ImportDirectoryTableEntry); 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>(LookupChunkSize)); 187 Addresses.push_back(make_unique<NullChunk>(LookupChunkSize)); 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 206