1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
|
//===- lib/ReaderWriter/PECOFF/IdataPass.h---------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file \brief This linker pass creates atoms for the DLL import
/// information. The defined atoms constructed in this pass will go into .idata
/// section, unless .idata section is merged with other section such as .data.
///
/// For the details of the .idata section format, see Microsoft PE/COFF
/// Specification section 5.4, The .idata Section.
///
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_PE_COFF_IDATA_PASS_H
#define LLD_READER_WRITER_PE_COFF_IDATA_PASS_H
#include "Atoms.h"
#include "lld/Core/File.h"
#include "lld/Core/Pass.h"
#include "lld/Core/Simple.h"
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
#include "llvm/Support/COFF.h"
#include <algorithm>
#include <map>
using llvm::COFF::ImportDirectoryTableEntry;
namespace lld {
namespace pecoff {
namespace idata {
class DLLNameAtom;
class HintNameAtom;
class ImportTableEntryAtom;
// A state object of this pass.
struct IdataContext {
IdataContext(MutableFile &f, VirtualFile &g, const PECOFFLinkingContext &c)
: file(f), dummyFile(g), ctx(c) {}
MutableFile &file;
VirtualFile &dummyFile;
const PECOFFLinkingContext &ctx;
};
/// The root class of all idata atoms.
class IdataAtom : public COFFLinkerInternalAtom {
public:
SectionChoice sectionChoice() const override { return sectionCustomRequired; }
StringRef customSectionName() const override { return ".idata"; }
ContentType contentType() const override { return typeData; }
ContentPermissions permissions() const override { return permR__; }
protected:
IdataAtom(IdataContext &context, std::vector<uint8_t> data);
};
/// A HintNameAtom represents a symbol that will be imported from a DLL at
/// runtime. It consists with an optional hint, which is a small integer, and a
/// symbol name.
///
/// A hint is an index of the export pointer table in a DLL. If the import
/// library and DLL is in sync (i.e., ".lib" and ".dll" is for the same version
/// or the symbol ordinal is maintained by hand with ".exp" file), the PE/COFF
/// loader can find the symbol quickly.
class HintNameAtom : public IdataAtom {
public:
HintNameAtom(IdataContext &context, uint16_t hint, StringRef importName);
StringRef getContentString() { return _importName; }
private:
std::vector<uint8_t> assembleRawContent(uint16_t hint, StringRef importName);
StringRef _importName;
};
class ImportTableEntryAtom : public IdataAtom {
public:
ImportTableEntryAtom(IdataContext &ctx, uint64_t contents,
StringRef sectionName)
: IdataAtom(ctx, assembleRawContent(contents, ctx.ctx.is64Bit())),
_sectionName(sectionName) {}
StringRef customSectionName() const override {
return _sectionName;
};
private:
std::vector<uint8_t> assembleRawContent(uint64_t contents, bool is64);
StringRef _sectionName;
};
/// An ImportDirectoryAtom includes information to load a DLL, including a DLL
/// name, symbols that will be resolved from the DLL, and the import address
/// table that are overwritten by the loader with the pointers to the referenced
/// items. The executable has one ImportDirectoryAtom per one imported DLL.
class ImportDirectoryAtom : public IdataAtom {
public:
ImportDirectoryAtom(IdataContext &context, StringRef loadName,
const std::vector<COFFSharedLibraryAtom *> &sharedAtoms)
: IdataAtom(context, std::vector<uint8_t>(20, 0)) {
addRelocations(context, loadName, sharedAtoms);
}
StringRef customSectionName() const override { return ".idata.d"; }
private:
void addRelocations(IdataContext &context, StringRef loadName,
const std::vector<COFFSharedLibraryAtom *> &sharedAtoms);
mutable llvm::BumpPtrAllocator _alloc;
};
/// The last NULL entry in the import directory.
class NullImportDirectoryAtom : public IdataAtom {
public:
explicit NullImportDirectoryAtom(IdataContext &context)
: IdataAtom(context, std::vector<uint8_t>(20, 0)) {}
StringRef customSectionName() const override { return ".idata.d"; }
};
/// The class for the the delay-load import table.
class DelayImportDirectoryAtom : public IdataAtom {
public:
DelayImportDirectoryAtom(
IdataContext &context, StringRef loadName,
const std::vector<COFFSharedLibraryAtom *> &sharedAtoms)
: IdataAtom(context, createContent()) {
addRelocations(context, loadName, sharedAtoms);
}
StringRef customSectionName() const override { return ".didat.d"; }
private:
std::vector<uint8_t> createContent();
void addRelocations(IdataContext &context, StringRef loadName,
const std::vector<COFFSharedLibraryAtom *> &sharedAtoms);
mutable llvm::BumpPtrAllocator _alloc;
};
/// Terminator of the delay-load import table. The content of this atom is all
/// zero.
class DelayNullImportDirectoryAtom : public IdataAtom {
public:
explicit DelayNullImportDirectoryAtom(IdataContext &context)
: IdataAtom(context, createContent()) {}
StringRef customSectionName() const override { return ".didat.d"; }
private:
std::vector<uint8_t> createContent() const {
return std::vector<uint8_t>(
sizeof(llvm::object::delay_import_directory_table_entry), 0);
}
};
class DelayImportAddressAtom : public IdataAtom {
public:
explicit DelayImportAddressAtom(IdataContext &context)
: IdataAtom(context, createContent(context.ctx)),
_align(context.ctx.is64Bit() ? 8 : 4) {}
StringRef customSectionName() const override { return ".data"; }
ContentPermissions permissions() const override { return permRW_; }
Alignment alignment() const override { return _align; }
private:
std::vector<uint8_t> createContent(const PECOFFLinkingContext &ctx) const {
return std::vector<uint8_t>(ctx.is64Bit() ? 8 : 4, 0);
}
Alignment _align;
};
// DelayLoaderAtom contains a wrapper function for __delayLoadHelper2.
class DelayLoaderAtom : public IdataAtom {
public:
DelayLoaderAtom(IdataContext &context, const Atom *impAtom,
const Atom *descAtom, const Atom *delayLoadHelperAtom);
StringRef customSectionName() const override { return ".text"; }
ContentPermissions permissions() const override { return permR_X; }
Alignment alignment() const override { return 1; }
private:
std::vector<uint8_t> createContent(MachineTypes machine) const;
};
} // namespace idata
class IdataPass : public lld::Pass {
public:
IdataPass(const PECOFFLinkingContext &ctx) : _dummyFile(ctx), _ctx(ctx) {}
void perform(std::unique_ptr<MutableFile> &file) override;
private:
std::map<StringRef, std::vector<COFFSharedLibraryAtom *>>
groupByLoadName(MutableFile &file);
void replaceSharedLibraryAtoms(MutableFile &file);
// A dummy file with which all the atoms created in the pass will be
// associated. Atoms need to be associated to an input file even if it's not
// read from a file, so we use this object.
VirtualFile _dummyFile;
const PECOFFLinkingContext &_ctx;
llvm::BumpPtrAllocator _alloc;
};
} // namespace pecoff
} // namespace lld
#endif
|