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
|
//===- 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 "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 Context {
Context(MutableFile &f, VirtualFile &g) : file(f), dummyFile(g) {}
MutableFile &file;
VirtualFile &dummyFile;
};
/// 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(Context &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(Context &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(Context &context, uint32_t contents,
StringRef sectionName)
: IdataAtom(context, assembleRawContent(contents)),
_sectionName(sectionName) {}
StringRef customSectionName() const override {
return _sectionName;
};
private:
std::vector<uint8_t> assembleRawContent(uint32_t contents);
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(Context &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(Context &context, StringRef loadName,
const std::vector<COFFSharedLibraryAtom *> &sharedAtoms);
std::vector<ImportTableEntryAtom *> createImportTableAtoms(
Context &context, const std::vector<COFFSharedLibraryAtom *> &sharedAtoms,
bool shouldAddReference, StringRef sectionName) const;
mutable llvm::BumpPtrAllocator _alloc;
};
/// The last NULL entry in the import directory.
class NullImportDirectoryAtom : public IdataAtom {
public:
explicit NullImportDirectoryAtom(Context &context)
: IdataAtom(context, std::vector<uint8_t>(20, 0)) {}
StringRef customSectionName() const override { return ".idata.d"; }
};
} // namespace idata
class IdataPass : public lld::Pass {
public:
IdataPass(const LinkingContext &ctx) : _dummyFile(ctx) {}
void perform(std::unique_ptr<MutableFile> &file) override;
private:
std::map<StringRef, std::vector<COFFSharedLibraryAtom *> >
groupByLoadName(MutableFile &file);
void replaceSharedLibraryAtoms(idata::Context &context);
// 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;
llvm::BumpPtrAllocator _alloc;
};
} // namespace pecoff
} // namespace lld
#endif
|