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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
|
//===- Core/NativeWriter.cpp - Creates a native object file ---------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <vector>
#include <map>
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/ArrayRef.h"
#include "lld/Core/File.h"
#include "lld/Core/NativeWriter.h"
#include "NativeFileFormat.h"
namespace lld {
///
/// Class for writing native object files.
///
class NativeWriter : public File::AtomHandler {
public:
/// construct writer for an lld::File object
NativeWriter(const lld::File& file) : _file(file) {
// visit all atoms
_file.forEachAtom(*this);
// construct file header based on atom information accumulated
makeHeader();
}
// write the lld::File in native format to the specified stream
void write(llvm::raw_ostream& out) {
out.write((char*)_headerBuffer, _headerBufferSize);
if (!_definedAtomIvars.empty())
out.write((char*)&_definedAtomIvars[0],
_definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1));
if (!_attributes.empty())
out.write((char*)&_attributes[0],
_attributes.size()*sizeof(NativeAtomAttributesV1));
if ( !_undefinedAtomIvars.empty() )
out.write((char*)&_undefinedAtomIvars[0],
_undefinedAtomIvars.size()*sizeof(NativeUndefinedAtomIvarsV1));
if (!_stringPool.empty())
out.write(&_stringPool[0], _stringPool.size());
if (!_contentPool.empty())
out.write((char*)&_contentPool[0], _contentPool.size());
}
private:
// visitor routine called by forEachAtom()
virtual void doDefinedAtom(const class DefinedAtom& atom) {
NativeDefinedAtomIvarsV1 ivar;
ivar.nameOffset = getNameOffset(atom);
ivar.attributesOffset = getAttributeOffset(atom);
ivar.contentOffset = getContentOffset(atom);
ivar.contentSize = atom.size();
_definedAtomIvars.push_back(ivar);
}
// visitor routine called by forEachAtom()
virtual void doUndefinedAtom(const class UndefinedAtom& atom) {
NativeUndefinedAtomIvarsV1 ivar;
ivar.nameOffset = getNameOffset(atom);
ivar.flags = (atom.weakImport() ? 1 : 0);
_undefinedAtomIvars.push_back(ivar);
}
// visitor routine called by forEachAtom()
virtual void doFile(const class File &) {
}
// fill out native file header and chunk directory
void makeHeader() {
const bool hasUndefines = !_undefinedAtomIvars.empty();
const int chunkCount = hasUndefines ? 5 : 4;
_headerBufferSize = sizeof(NativeFileHeader)
+ chunkCount*sizeof(NativeChunk);
_headerBuffer = reinterpret_cast<NativeFileHeader*>
(operator new(_headerBufferSize, std::nothrow));
NativeChunk *chunks =
reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
+ sizeof(NativeFileHeader));
memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC, 16);
_headerBuffer->endian = NFH_LittleEndian;
_headerBuffer->architecture = 0;
_headerBuffer->fileSize = 0;
_headerBuffer->chunkCount = chunkCount;
// create chunk for atom ivar array
int nextIndex = 0;
NativeChunk& chd = chunks[nextIndex++];
chd.signature = NCS_DefinedAtomsV1;
chd.fileOffset = _headerBufferSize;
chd.fileSize = _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1);
chd.elementCount = _definedAtomIvars.size();
uint32_t nextFileOffset = chd.fileOffset + chd.fileSize;
// create chunk for attributes
NativeChunk& cha = chunks[nextIndex++];
cha.signature = NCS_AttributesArrayV1;
cha.fileOffset = nextFileOffset;
cha.fileSize = _attributes.size()*sizeof(NativeAtomAttributesV1);
cha.elementCount = _attributes.size();
nextFileOffset = cha.fileOffset + cha.fileSize;
// create chunk for undefined atom array
if ( hasUndefines ) {
NativeChunk& chu = chunks[nextIndex++];
chu.signature = NCS_UndefinedAtomsV1;
chu.fileOffset = nextFileOffset;
chu.fileSize = _undefinedAtomIvars.size() *
sizeof(NativeUndefinedAtomIvarsV1);
chu.elementCount = _undefinedAtomIvars.size();
nextFileOffset = chu.fileOffset + chu.fileSize;
}
// create chunk for symbol strings
NativeChunk& chs = chunks[nextIndex++];
chs.signature = NCS_Strings;
chs.fileOffset = nextFileOffset;
chs.fileSize = _stringPool.size();
chs.elementCount = _stringPool.size();
nextFileOffset = chs.fileOffset + chs.fileSize;
// create chunk for content
NativeChunk& chc = chunks[nextIndex++];
chc.signature = NCS_Content;
chc.fileOffset = nextFileOffset;
chc.fileSize = _contentPool.size();
chc.elementCount = _contentPool.size();
nextFileOffset = chc.fileOffset + chc.fileSize;
_headerBuffer->fileSize = nextFileOffset;
}
// append atom name to string pool and return offset
uint32_t getNameOffset(const Atom& atom) {
return this->getNameOffset(atom.name());
}
// append atom name to string pool and return offset
uint32_t getNameOffset(llvm::StringRef name) {
uint32_t result = _stringPool.size();
_stringPool.insert(_stringPool.end(), name.size()+1, 0);
strcpy(&_stringPool[result], name.data());
return result;
}
// append atom cotent to content pool and return offset
uint32_t getContentOffset(const class DefinedAtom& atom) {
if ( atom.contentType() == DefinedAtom::typeZeroFill )
return 0;
uint32_t result = _contentPool.size();
llvm::ArrayRef<uint8_t> cont = atom.rawContent();
_contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
return result;
}
// reuse existing attributes entry or create a new one and return offet
uint32_t getAttributeOffset(const class DefinedAtom& atom) {
NativeAtomAttributesV1 attrs;
computeAttributesV1(atom, attrs);
for(unsigned int i=0; i < _attributes.size(); ++i) {
if ( !memcmp(&_attributes[i], &attrs, sizeof(NativeAtomAttributesV1)) ) {
// found that this set of attributes already used, so re-use
return i * sizeof(NativeAtomAttributesV1);
}
}
// append new attribute set to end
uint32_t result = _attributes.size() * sizeof(NativeAtomAttributesV1);
_attributes.push_back(attrs);
return result;
}
uint32_t sectionNameOffset(const class DefinedAtom& atom) {
// if section based on content, then no custom section name available
if ( atom.sectionChoice() == DefinedAtom::sectionBasedOnContent )
return 0;
llvm::StringRef name = atom.customSectionName();
assert( ! name.empty() );
// look to see if this section name was used by another atom
for(NameToOffsetVector::iterator it=_sectionNames.begin();
it != _sectionNames.end(); ++it) {
if ( name.equals(it->first) )
return it->second;
}
// first use of this section name
uint32_t result = this->getNameOffset(name);
_sectionNames.push_back(
std::make_pair<llvm::StringRef, uint32_t>(name, result));
return result;
}
void computeAttributesV1(const class DefinedAtom& atom,
NativeAtomAttributesV1& attrs) {
attrs.sectionNameOffset = sectionNameOffset(atom);
attrs.align2 = atom.alignment().powerOf2;
attrs.alignModulus = atom.alignment().modulus;
attrs.internalName = atom.internalName();
attrs.scope = atom.scope();
attrs.interposable = atom.interposable();
attrs.merge = atom.merge();
attrs.contentType = atom.contentType();
attrs.sectionChoice = atom.sectionChoice();
attrs.deadStrip = atom.deadStrip();
attrs.permissions = atom.permissions();
attrs.thumb = atom.isThumb();
attrs.alias = atom.isAlias();
}
typedef std::vector<std::pair<llvm::StringRef, uint32_t> > NameToOffsetVector;
const lld::File& _file;
NativeFileHeader* _headerBuffer;
size_t _headerBufferSize;
std::vector<char> _stringPool;
std::vector<uint8_t> _contentPool;
std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
std::vector<NativeAtomAttributesV1> _attributes;
std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
NameToOffsetVector _sectionNames;
};
/// writeNativeObjectFile - writes the lld::File object in native object
/// file format to the specified stream.
int writeNativeObjectFile(const lld::File &file, llvm::raw_ostream &out) {
NativeWriter writer(file);
writer.write(out);
return 0;
}
/// writeNativeObjectFile - writes the lld::File object in native object
/// file format to the specified file path.
int writeNativeObjectFile(const lld::File& file, llvm::StringRef path) {
std::string errorInfo;
llvm::raw_fd_ostream out(path.data(), errorInfo, llvm::raw_fd_ostream::F_Binary);
if ( !errorInfo.empty() )
return -1;
return writeNativeObjectFile(file, out);
}
} // namespace lld
|