blob: e65573e38d49f1618d3869cbf2d57542181d33a8 [file] [log] [blame]
Nick Kledzik55fd6be2012-01-16 22:03:44 +00001//===- Core/NativeWriter.cpp - Creates a native object file ---------------===//
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#include <vector>
Nick Kledzik55fd6be2012-01-16 22:03:44 +000011
12#include "llvm/ADT/StringRef.h"
13#include "llvm/ADT/ArrayRef.h"
Nick Kledzik49d6cc82012-02-15 00:38:09 +000014#include "llvm/ADT/DenseMap.h"
Nick Kledzik55fd6be2012-01-16 22:03:44 +000015
16#include "lld/Core/File.h"
17#include "lld/Core/NativeWriter.h"
18
19#include "NativeFileFormat.h"
20
21
22namespace lld {
23
24
25///
26/// Class for writing native object files.
27///
Nick Kledzik1a6615d2012-03-08 00:18:30 +000028class NativeWriter {
Nick Kledzik55fd6be2012-01-16 22:03:44 +000029public:
30 /// construct writer for an lld::File object
31 NativeWriter(const lld::File& file) : _file(file) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +000032 // reserve first byte for unnamed atoms
33 _stringPool.push_back('\0');
Nick Kledzik55fd6be2012-01-16 22:03:44 +000034 // visit all atoms
Nick Kledzik1a6615d2012-03-08 00:18:30 +000035 for(File::defined_iterator it=file.definedAtomsBegin(),
36 end=file.definedAtomsEnd();
37 it != end; ++it) {
38 this->addIVarsForDefinedAtom(**it);
39 }
40 for(File::undefined_iterator it=file.undefinedAtomsBegin(),
41 end=file.undefinedAtomsEnd();
42 it != end; ++it) {
43 this->addIVarsForUndefinedAtom(**it);
44 }
45 for(File::shared_library_iterator it=file.sharedLibraryAtomsBegin(),
46 end=file.sharedLibraryAtomsEnd();
47 it != end; ++it) {
48 this->addIVarsForSharedLibraryAtom(**it);
49 }
50 for(File::absolute_iterator it=file.absoluteAtomsBegin(),
51 end=file.absoluteAtomsEnd();
52 it != end; ++it) {
53 this->addIVarsForAbsoluteAtom(**it);
54 }
55
56
57
Nick Kledzik55fd6be2012-01-16 22:03:44 +000058 // construct file header based on atom information accumulated
59 makeHeader();
60 }
61
62 // write the lld::File in native format to the specified stream
63 void write(llvm::raw_ostream& out) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +000064 assert( out.tell() == 0 );
Nick Kledzik55fd6be2012-01-16 22:03:44 +000065 out.write((char*)_headerBuffer, _headerBufferSize);
Nick Kledzik49d6cc82012-02-15 00:38:09 +000066
67 if (!_definedAtomIvars.empty()) {
68 assert( out.tell() == findChunk(NCS_DefinedAtomsV1).fileOffset );
Michael J. Spencer8c36f452012-01-31 21:46:41 +000069 out.write((char*)&_definedAtomIvars[0],
70 _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1));
Nick Kledzik49d6cc82012-02-15 00:38:09 +000071 }
72
73 if (!_attributes.empty()) {
74 assert( out.tell() == findChunk(NCS_AttributesArrayV1).fileOffset );
Michael J. Spencer8c36f452012-01-31 21:46:41 +000075 out.write((char*)&_attributes[0],
76 _attributes.size()*sizeof(NativeAtomAttributesV1));
Nick Kledzik49d6cc82012-02-15 00:38:09 +000077 }
78
79 if ( !_undefinedAtomIvars.empty() ) {
80 assert( out.tell() == findChunk(NCS_UndefinedAtomsV1).fileOffset );
Nick Kledzik23384e82012-02-07 02:59:54 +000081 out.write((char*)&_undefinedAtomIvars[0],
82 _undefinedAtomIvars.size()*sizeof(NativeUndefinedAtomIvarsV1));
Nick Kledzik49d6cc82012-02-15 00:38:09 +000083 }
Nick Kledzik6bc04c62012-02-22 21:56:59 +000084
85 if ( !_sharedLibraryAtomIvars.empty() ) {
86 assert( out.tell() == findChunk(NCS_SharedLibraryAtomsV1).fileOffset );
87 out.write((char*)&_sharedLibraryAtomIvars[0],
88 _sharedLibraryAtomIvars.size()
89 * sizeof(NativeSharedLibraryAtomIvarsV1));
90 }
91
92 if ( !_absoluteAtomIvars.empty() ) {
93 assert( out.tell() == findChunk(NCS_AbsoluteAtomsV1).fileOffset );
94 out.write((char*)&_absoluteAtomIvars[0],
95 _absoluteAtomIvars.size()
96 * sizeof(NativeAbsoluteAtomIvarsV1));
97 }
98
Nick Kledzik49d6cc82012-02-15 00:38:09 +000099 if (!_stringPool.empty()) {
100 assert( out.tell() == findChunk(NCS_Strings).fileOffset );
Michael J. Spencer8c36f452012-01-31 21:46:41 +0000101 out.write(&_stringPool[0], _stringPool.size());
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000102 }
103
104 if ( !_references.empty() ) {
105 assert( out.tell() == findChunk(NCS_ReferencesArrayV1).fileOffset );
106 out.write((char*)&_references[0],
107 _references.size()*sizeof(NativeReferenceIvarsV1));
108 }
109
110 if ( !_targetsTableIndex.empty() ) {
111 assert( out.tell() == findChunk(NCS_TargetsTable).fileOffset );
112 writeTargetTable(out);
113 }
114
115 if ( !_addendsTableIndex.empty() ) {
116 assert( out.tell() == findChunk(NCS_AddendsTable).fileOffset );
117 writeAddendTable(out);
118 }
119
120 if (!_contentPool.empty()) {
121 assert( out.tell() == findChunk(NCS_Content).fileOffset );
Nick Kledzik23384e82012-02-07 02:59:54 +0000122 out.write((char*)&_contentPool[0], _contentPool.size());
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000123 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000124 }
125
126private:
127
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000128 void addIVarsForDefinedAtom(const DefinedAtom& atom) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000129 _definedAtomIndex[&atom] = _definedAtomIvars.size();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000130 NativeDefinedAtomIvarsV1 ivar;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000131 unsigned refsCount;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000132 ivar.nameOffset = getNameOffset(atom);
133 ivar.attributesOffset = getAttributeOffset(atom);
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000134 ivar.referencesStartIndex = getReferencesIndex(atom, refsCount);
135 ivar.referencesCount = refsCount;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000136 ivar.contentOffset = getContentOffset(atom);
137 ivar.contentSize = atom.size();
138 _definedAtomIvars.push_back(ivar);
139 }
140
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000141 void addIVarsForUndefinedAtom(const UndefinedAtom& atom) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000142 _undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
Nick Kledzik23384e82012-02-07 02:59:54 +0000143 NativeUndefinedAtomIvarsV1 ivar;
144 ivar.nameOffset = getNameOffset(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000145 ivar.flags = (atom.canBeNull() & 0x03);
Nick Kledzik23384e82012-02-07 02:59:54 +0000146 _undefinedAtomIvars.push_back(ivar);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000147 }
148
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000149 void addIVarsForSharedLibraryAtom(const SharedLibraryAtom& atom) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000150 _sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
151 NativeSharedLibraryAtomIvarsV1 ivar;
152 ivar.nameOffset = getNameOffset(atom);
153 ivar.loadNameOffset = getSharedLibraryNameOffset(atom.loadName());
154 ivar.flags = atom.canBeNullAtRuntime();
155 _sharedLibraryAtomIvars.push_back(ivar);
156 }
157
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000158 void addIVarsForAbsoluteAtom(const AbsoluteAtom& atom) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000159 _absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
160 NativeAbsoluteAtomIvarsV1 ivar;
161 ivar.nameOffset = getNameOffset(atom);
162 ivar.reserved = 0;
163 ivar.value = atom.value();
164 _absoluteAtomIvars.push_back(ivar);
165 }
166
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000167 // fill out native file header and chunk directory
168 void makeHeader() {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000169 const bool hasDefines = !_definedAtomIvars.empty();
Nick Kledzik23384e82012-02-07 02:59:54 +0000170 const bool hasUndefines = !_undefinedAtomIvars.empty();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000171 const bool hasSharedLibraries = !_sharedLibraryAtomIvars.empty();
172 const bool hasAbsolutes = !_absoluteAtomIvars.empty();
173 const bool hasReferences = !_references.empty();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000174 const bool hasTargetsTable = !_targetsTableIndex.empty();
175 const bool hasAddendTable = !_addendsTableIndex.empty();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000176 const bool hasContent = !_contentPool.empty();
177
178 int chunkCount = 1; // always have string pool chunk
179 if ( hasDefines ) chunkCount += 2;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000180 if ( hasUndefines ) ++chunkCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000181 if ( hasSharedLibraries ) ++chunkCount;
182 if ( hasAbsolutes ) ++chunkCount;
183 if ( hasReferences ) ++chunkCount;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000184 if ( hasTargetsTable ) ++chunkCount;
185 if ( hasAddendTable ) ++chunkCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000186 if ( hasContent ) ++chunkCount;
187
Nick Kledzik23384e82012-02-07 02:59:54 +0000188 _headerBufferSize = sizeof(NativeFileHeader)
189 + chunkCount*sizeof(NativeChunk);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000190 _headerBuffer = reinterpret_cast<NativeFileHeader*>
191 (operator new(_headerBufferSize, std::nothrow));
Michael J. Spencerb2bd7332012-01-31 21:45:53 +0000192 NativeChunk *chunks =
193 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
194 + sizeof(NativeFileHeader));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000195 memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC, 16);
196 _headerBuffer->endian = NFH_LittleEndian;
197 _headerBuffer->architecture = 0;
198 _headerBuffer->fileSize = 0;
Nick Kledzik23384e82012-02-07 02:59:54 +0000199 _headerBuffer->chunkCount = chunkCount;
200
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000201 // create chunk for defined atom ivar array
Nick Kledzik23384e82012-02-07 02:59:54 +0000202 int nextIndex = 0;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000203 uint32_t nextFileOffset = _headerBufferSize;
204 if ( hasDefines ) {
205 NativeChunk& chd = chunks[nextIndex++];
206 chd.signature = NCS_DefinedAtomsV1;
207 chd.fileOffset = nextFileOffset;
208 chd.fileSize = _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1);
209 chd.elementCount = _definedAtomIvars.size();
210 nextFileOffset = chd.fileOffset + chd.fileSize;
Nick Kledzik23384e82012-02-07 02:59:54 +0000211
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000212 // create chunk for attributes
213 NativeChunk& cha = chunks[nextIndex++];
214 cha.signature = NCS_AttributesArrayV1;
215 cha.fileOffset = nextFileOffset;
216 cha.fileSize = _attributes.size()*sizeof(NativeAtomAttributesV1);
217 cha.elementCount = _attributes.size();
218 nextFileOffset = cha.fileOffset + cha.fileSize;
219 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000220
Nick Kledzik23384e82012-02-07 02:59:54 +0000221 // create chunk for undefined atom array
222 if ( hasUndefines ) {
223 NativeChunk& chu = chunks[nextIndex++];
224 chu.signature = NCS_UndefinedAtomsV1;
225 chu.fileOffset = nextFileOffset;
226 chu.fileSize = _undefinedAtomIvars.size() *
227 sizeof(NativeUndefinedAtomIvarsV1);
228 chu.elementCount = _undefinedAtomIvars.size();
229 nextFileOffset = chu.fileOffset + chu.fileSize;
230 }
231
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000232 // create chunk for shared library atom array
233 if ( hasSharedLibraries ) {
234 NativeChunk& chsl = chunks[nextIndex++];
235 chsl.signature = NCS_SharedLibraryAtomsV1;
236 chsl.fileOffset = nextFileOffset;
237 chsl.fileSize = _sharedLibraryAtomIvars.size() *
238 sizeof(NativeSharedLibraryAtomIvarsV1);
239 chsl.elementCount = _sharedLibraryAtomIvars.size();
240 nextFileOffset = chsl.fileOffset + chsl.fileSize;
241 }
242
243 // create chunk for shared library atom array
244 if ( hasAbsolutes ) {
245 NativeChunk& chsl = chunks[nextIndex++];
246 chsl.signature = NCS_AbsoluteAtomsV1;
247 chsl.fileOffset = nextFileOffset;
248 chsl.fileSize = _absoluteAtomIvars.size() *
249 sizeof(NativeAbsoluteAtomIvarsV1);
250 chsl.elementCount = _absoluteAtomIvars.size();
251 nextFileOffset = chsl.fileOffset + chsl.fileSize;
252 }
253
Nick Kledzik23384e82012-02-07 02:59:54 +0000254 // create chunk for symbol strings
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000255 // pad end of string pool to 4-bytes
256 while ( (_stringPool.size() % 4) != 0 )
257 _stringPool.push_back('\0');
Nick Kledzik23384e82012-02-07 02:59:54 +0000258 NativeChunk& chs = chunks[nextIndex++];
259 chs.signature = NCS_Strings;
260 chs.fileOffset = nextFileOffset;
261 chs.fileSize = _stringPool.size();
262 chs.elementCount = _stringPool.size();
263 nextFileOffset = chs.fileOffset + chs.fileSize;
264
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000265 // create chunk for references
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000266 if ( hasReferences ) {
267 NativeChunk& chr = chunks[nextIndex++];
268 chr.signature = NCS_ReferencesArrayV1;
269 chr.fileOffset = nextFileOffset;
270 chr.fileSize = _references.size() * sizeof(NativeReferenceIvarsV1);
271 chr.elementCount = _references.size();
272 nextFileOffset = chr.fileOffset + chr.fileSize;
273 }
274
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000275 // create chunk for target table
276 if ( hasTargetsTable ) {
277 NativeChunk& cht = chunks[nextIndex++];
278 cht.signature = NCS_TargetsTable;
279 cht.fileOffset = nextFileOffset;
280 cht.fileSize = _targetsTableIndex.size() * sizeof(uint32_t);
281 cht.elementCount = _targetsTableIndex.size();
282 nextFileOffset = cht.fileOffset + cht.fileSize;
283 }
284
285 // create chunk for addend table
286 if ( hasAddendTable ) {
287 NativeChunk& chad = chunks[nextIndex++];
288 chad.signature = NCS_AddendsTable;
289 chad.fileOffset = nextFileOffset;
290 chad.fileSize = _addendsTableIndex.size() * sizeof(Reference::Addend);
291 chad.elementCount = _addendsTableIndex.size();
292 nextFileOffset = chad.fileOffset + chad.fileSize;
293 }
294
Nick Kledzik23384e82012-02-07 02:59:54 +0000295 // create chunk for content
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000296 if ( hasContent ) {
297 NativeChunk& chc = chunks[nextIndex++];
298 chc.signature = NCS_Content;
299 chc.fileOffset = nextFileOffset;
300 chc.fileSize = _contentPool.size();
301 chc.elementCount = _contentPool.size();
302 nextFileOffset = chc.fileOffset + chc.fileSize;
303 }
304
Nick Kledzik23384e82012-02-07 02:59:54 +0000305 _headerBuffer->fileSize = nextFileOffset;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000306 }
307
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000308 // scan header to find particular chunk
309 NativeChunk& findChunk(uint32_t signature) {
310 const uint32_t chunkCount = _headerBuffer->chunkCount;
311 NativeChunk* chunks =
312 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
313 + sizeof(NativeFileHeader));
314 for (uint32_t i=0; i < chunkCount; ++i) {
315 if ( chunks[i].signature == signature )
316 return chunks[i];
317 }
318 assert(0 && "findChunk() signature not found");
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000319 static NativeChunk x; return x; // suppress warning
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000320 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000321
322 // append atom name to string pool and return offset
Nick Kledzik23384e82012-02-07 02:59:54 +0000323 uint32_t getNameOffset(const Atom& atom) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000324 return this->getNameOffset(atom.name());
325 }
326
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000327 // check if name is already in pool or append and return offset
328 uint32_t getSharedLibraryNameOffset(llvm::StringRef name) {
329 assert( ! name.empty() );
330 // look to see if this library name was used by another atom
331 for(NameToOffsetVector::iterator it = _sharedLibraryNames.begin();
332 it != _sharedLibraryNames.end(); ++it) {
333 if ( name.equals(it->first) )
334 return it->second;
335 }
336 // first use of this library name
337 uint32_t result = this->getNameOffset(name);
Michael J. Spencere753cbc2012-03-09 05:27:43 +0000338 _sharedLibraryNames.push_back(std::make_pair(name, result));
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000339 return result;
340 }
341
342 // append atom name to string pool and return offset
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000343 uint32_t getNameOffset(llvm::StringRef name) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000344 if ( name.empty() )
345 return 0;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000346 uint32_t result = _stringPool.size();
Michael J. Spencerb5ef4df2012-03-09 05:27:20 +0000347 _stringPool.insert(_stringPool.end(), name.begin(), name.end());
348 _stringPool.push_back(0);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000349 return result;
350 }
351
352 // append atom cotent to content pool and return offset
353 uint32_t getContentOffset(const class DefinedAtom& atom) {
354 if ( atom.contentType() == DefinedAtom::typeZeroFill )
355 return 0;
356 uint32_t result = _contentPool.size();
357 llvm::ArrayRef<uint8_t> cont = atom.rawContent();
Michael J. Spencer846fe662012-01-31 21:46:05 +0000358 _contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000359 return result;
360 }
361
362 // reuse existing attributes entry or create a new one and return offet
363 uint32_t getAttributeOffset(const class DefinedAtom& atom) {
364 NativeAtomAttributesV1 attrs;
365 computeAttributesV1(atom, attrs);
366 for(unsigned int i=0; i < _attributes.size(); ++i) {
367 if ( !memcmp(&_attributes[i], &attrs, sizeof(NativeAtomAttributesV1)) ) {
368 // found that this set of attributes already used, so re-use
369 return i * sizeof(NativeAtomAttributesV1);
370 }
371 }
372 // append new attribute set to end
373 uint32_t result = _attributes.size() * sizeof(NativeAtomAttributesV1);
374 _attributes.push_back(attrs);
375 return result;
376 }
377
378 uint32_t sectionNameOffset(const class DefinedAtom& atom) {
379 // if section based on content, then no custom section name available
380 if ( atom.sectionChoice() == DefinedAtom::sectionBasedOnContent )
381 return 0;
382 llvm::StringRef name = atom.customSectionName();
383 assert( ! name.empty() );
384 // look to see if this section name was used by another atom
385 for(NameToOffsetVector::iterator it=_sectionNames.begin();
386 it != _sectionNames.end(); ++it) {
387 if ( name.equals(it->first) )
388 return it->second;
389 }
390 // first use of this section name
391 uint32_t result = this->getNameOffset(name);
Michael J. Spencere753cbc2012-03-09 05:27:43 +0000392 _sectionNames.push_back(std::make_pair(name, result));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000393 return result;
394 }
395
396 void computeAttributesV1(const class DefinedAtom& atom,
397 NativeAtomAttributesV1& attrs) {
398 attrs.sectionNameOffset = sectionNameOffset(atom);
399 attrs.align2 = atom.alignment().powerOf2;
400 attrs.alignModulus = atom.alignment().modulus;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000401 attrs.scope = atom.scope();
402 attrs.interposable = atom.interposable();
403 attrs.merge = atom.merge();
404 attrs.contentType = atom.contentType();
405 attrs.sectionChoice = atom.sectionChoice();
406 attrs.deadStrip = atom.deadStrip();
407 attrs.permissions = atom.permissions();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000408 //attrs.thumb = atom.isThumb();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000409 attrs.alias = atom.isAlias();
410 }
411
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000412 // add references for this atom in a contiguous block in NCS_ReferencesArrayV1
413 uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& count) {
414 count = 0;
415 size_t startRefSize = _references.size();
416 uint32_t result = startRefSize;
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000417 for (auto it=atom.referencesBegin(), end=atom.referencesEnd();
418 it != end; ++it) {
419 const Reference* ref = *it;
420 NativeReferenceIvarsV1 nref;
421 nref.offsetInAtom = ref->offsetInAtom();
422 nref.kind = ref->kind();
423 nref.targetIndex = this->getTargetIndex(ref->target());
424 nref.addendIndex = this->getAddendIndex(ref->addend());
425 _references.push_back(nref);
426 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000427 count = _references.size() - startRefSize;
428 if ( count == 0 )
429 return 0;
430 else
431 return result;
432 }
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000433
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000434 uint32_t getTargetIndex(const Atom* target) {
435 TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
436 if ( pos != _targetsTableIndex.end() ) {
437 return pos->second;
438 }
439 uint32_t result = _targetsTableIndex.size();
440 _targetsTableIndex[target] = result;
441 return result;
442 }
443
444 void writeTargetTable(llvm::raw_ostream& out) {
445 // Build table of target indexes
446 uint32_t maxTargetIndex = _targetsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000447 assert(maxTargetIndex > 0);
448 std::vector<uint32_t> targetIndexes(maxTargetIndex);
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000449 for (TargetToIndex::iterator it = _targetsTableIndex.begin();
450 it != _targetsTableIndex.end(); ++it) {
451 const Atom* atom = it->first;
452 uint32_t targetIndex = it->second;
453 assert(targetIndex < maxTargetIndex);
454 uint32_t atomIndex = 0;
455 TargetToIndex::iterator pos = _definedAtomIndex.find(atom);
456 if ( pos != _definedAtomIndex.end() ) {
457 atomIndex = pos->second;
458 }
459 else {
460 pos = _undefinedAtomIndex.find(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000461 if ( pos != _undefinedAtomIndex.end() ) {
462 atomIndex = pos->second + _definedAtomIvars.size();
463 }
464 else {
465 pos = _sharedLibraryAtomIndex.find(atom);
466 if ( pos != _sharedLibraryAtomIndex.end() ) {
467 assert(pos != _sharedLibraryAtomIndex.end());
468 atomIndex = pos->second
469 + _definedAtomIvars.size()
470 + _undefinedAtomIndex.size();
471 }
472 else {
473 pos = _absoluteAtomIndex.find(atom);
474 assert(pos != _absoluteAtomIndex.end());
475 atomIndex = pos->second
476 + _definedAtomIvars.size()
477 + _undefinedAtomIndex.size()
478 + _sharedLibraryAtomIndex.size();
479 }
480 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000481 }
482 targetIndexes[targetIndex] = atomIndex;
483 }
484 // write table
485 out.write((char*)&targetIndexes[0], maxTargetIndex*sizeof(uint32_t));
486 }
487
488 uint32_t getAddendIndex(Reference::Addend addend) {
489 if ( addend == 0 )
490 return 0; // addend index zero is used to mean "no addend"
491 AddendToIndex::const_iterator pos = _addendsTableIndex.find(addend);
492 if ( pos != _addendsTableIndex.end() ) {
493 return pos->second;
494 }
495 uint32_t result = _addendsTableIndex.size() + 1; // one-based index
496 _addendsTableIndex[addend] = result;
497 return result;
498 }
499
500 void writeAddendTable(llvm::raw_ostream& out) {
501 // Build table of addends
502 uint32_t maxAddendIndex = _addendsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000503 std::vector<Reference::Addend> addends(maxAddendIndex);
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000504 for (AddendToIndex::iterator it = _addendsTableIndex.begin();
505 it != _addendsTableIndex.end(); ++it) {
506 Reference::Addend addend = it->first;
507 uint32_t index = it->second;
508 assert(index <= maxAddendIndex);
509 addends[index-1] = addend;
510 }
511 // write table
512 out.write((char*)&addends[0], maxAddendIndex*sizeof(Reference::Addend));
513 }
514
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000515 typedef std::vector<std::pair<llvm::StringRef, uint32_t> > NameToOffsetVector;
516
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000517 typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex;
518 typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex;
519
Nick Kledzik23384e82012-02-07 02:59:54 +0000520 const lld::File& _file;
521 NativeFileHeader* _headerBuffer;
522 size_t _headerBufferSize;
523 std::vector<char> _stringPool;
524 std::vector<uint8_t> _contentPool;
525 std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
526 std::vector<NativeAtomAttributesV1> _attributes;
527 std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000528 std::vector<NativeSharedLibraryAtomIvarsV1> _sharedLibraryAtomIvars;
529 std::vector<NativeAbsoluteAtomIvarsV1> _absoluteAtomIvars;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000530 std::vector<NativeReferenceIvarsV1> _references;
531 TargetToIndex _targetsTableIndex;
532 TargetToIndex _definedAtomIndex;
533 TargetToIndex _undefinedAtomIndex;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000534 TargetToIndex _sharedLibraryAtomIndex;
535 TargetToIndex _absoluteAtomIndex;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000536 AddendToIndex _addendsTableIndex;
Nick Kledzik23384e82012-02-07 02:59:54 +0000537 NameToOffsetVector _sectionNames;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000538 NameToOffsetVector _sharedLibraryNames;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000539};
540
541
542
543
544
545/// writeNativeObjectFile - writes the lld::File object in native object
546/// file format to the specified stream.
547int writeNativeObjectFile(const lld::File &file, llvm::raw_ostream &out) {
548 NativeWriter writer(file);
549 writer.write(out);
550 return 0;
551}
552
553/// writeNativeObjectFile - writes the lld::File object in native object
554/// file format to the specified file path.
555int writeNativeObjectFile(const lld::File& file, llvm::StringRef path) {
556 std::string errorInfo;
557 llvm::raw_fd_ostream out(path.data(), errorInfo, llvm::raw_fd_ostream::F_Binary);
558 if ( !errorInfo.empty() )
559 return -1;
560 return writeNativeObjectFile(file, out);
561}
562
563} // namespace lld