blob: 024d190ee80c2994ef23dd0f65fa9d9d3c953031 [file] [log] [blame]
Rui Ueyama4b22fa72015-06-07 01:15:04 +00001//===- 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
27using namespace llvm;
28using namespace llvm::object;
29using namespace llvm::support::endian;
30using namespace llvm::COFF;
31using llvm::RoundUpToAlignment;
32
Rui Ueyama94df7132015-06-07 03:55:28 +000033static const size_t LookupChunkSize = sizeof(uint64_t);
34static const size_t DirectoryChunkSize = sizeof(ImportDirectoryTableEntry);
Rui Ueyama4b22fa72015-06-07 01:15:04 +000035
36namespace lld {
37namespace coff {
38
39// A chunk for the import descriptor table.
40class HintNameChunk : public Chunk {
41public:
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
55private:
56 StringRef Name;
57 uint16_t Hint;
58};
59
60// A chunk for the import descriptor table.
61class LookupChunk : public Chunk {
62public:
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.
76class OrdinalOnlyChunk : public Chunk {
77public:
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.
91class DirectoryChunk : public Chunk {
92public:
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.
110class NullChunk : public Chunk {
111public:
112 explicit NullChunk(size_t N) : Size(N) {}
113 bool hasData() const override { return false; }
114 size_t getSize() const override { return Size; }
115
116private:
117 size_t Size;
118};
119
120uint64_t IdataContents::getDirSize() {
121 return Dirs.size() * DirectoryChunkSize;
122}
123
124uint64_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.
130std::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
150void 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.
Rui Ueyamac6b87362015-06-07 22:00:28 +0000186 Lookups.push_back(make_unique<NullChunk>(LookupChunkSize));
187 Addresses.push_back(make_unique<NullChunk>(LookupChunkSize));
Rui Ueyama4b22fa72015-06-07 01:15:04 +0000188
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