blob: a95a514980805c24cd37925f30913ccce3e32c35 [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>
11#include <map>
12
13#include "llvm/ADT/StringRef.h"
14#include "llvm/ADT/ArrayRef.h"
Nick Kledzik49d6cc82012-02-15 00:38:09 +000015#include "llvm/ADT/DenseMap.h"
Nick Kledzik55fd6be2012-01-16 22:03:44 +000016
17#include "lld/Core/File.h"
18#include "lld/Core/NativeWriter.h"
19
20#include "NativeFileFormat.h"
21
22
23namespace lld {
24
25
26///
27/// Class for writing native object files.
28///
Nick Kledzik49d6cc82012-02-15 00:38:09 +000029class NativeWriter : public File::AtomHandler,
30 public DefinedAtom::ReferenceHandler {
Nick Kledzik55fd6be2012-01-16 22:03:44 +000031public:
32 /// construct writer for an lld::File object
33 NativeWriter(const lld::File& file) : _file(file) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +000034 // reserve first byte for unnamed atoms
35 _stringPool.push_back('\0');
Nick Kledzik55fd6be2012-01-16 22:03:44 +000036 // visit all atoms
37 _file.forEachAtom(*this);
38 // construct file header based on atom information accumulated
39 makeHeader();
40 }
41
42 // write the lld::File in native format to the specified stream
43 void write(llvm::raw_ostream& out) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +000044 assert( out.tell() == 0 );
Nick Kledzik55fd6be2012-01-16 22:03:44 +000045 out.write((char*)_headerBuffer, _headerBufferSize);
Nick Kledzik49d6cc82012-02-15 00:38:09 +000046
47 if (!_definedAtomIvars.empty()) {
48 assert( out.tell() == findChunk(NCS_DefinedAtomsV1).fileOffset );
Michael J. Spencer8c36f452012-01-31 21:46:41 +000049 out.write((char*)&_definedAtomIvars[0],
50 _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1));
Nick Kledzik49d6cc82012-02-15 00:38:09 +000051 }
52
53 if (!_attributes.empty()) {
54 assert( out.tell() == findChunk(NCS_AttributesArrayV1).fileOffset );
Michael J. Spencer8c36f452012-01-31 21:46:41 +000055 out.write((char*)&_attributes[0],
56 _attributes.size()*sizeof(NativeAtomAttributesV1));
Nick Kledzik49d6cc82012-02-15 00:38:09 +000057 }
58
59 if ( !_undefinedAtomIvars.empty() ) {
60 assert( out.tell() == findChunk(NCS_UndefinedAtomsV1).fileOffset );
Nick Kledzik23384e82012-02-07 02:59:54 +000061 out.write((char*)&_undefinedAtomIvars[0],
62 _undefinedAtomIvars.size()*sizeof(NativeUndefinedAtomIvarsV1));
Nick Kledzik49d6cc82012-02-15 00:38:09 +000063 }
Nick Kledzik6bc04c62012-02-22 21:56:59 +000064
65 if ( !_sharedLibraryAtomIvars.empty() ) {
66 assert( out.tell() == findChunk(NCS_SharedLibraryAtomsV1).fileOffset );
67 out.write((char*)&_sharedLibraryAtomIvars[0],
68 _sharedLibraryAtomIvars.size()
69 * sizeof(NativeSharedLibraryAtomIvarsV1));
70 }
71
72 if ( !_absoluteAtomIvars.empty() ) {
73 assert( out.tell() == findChunk(NCS_AbsoluteAtomsV1).fileOffset );
74 out.write((char*)&_absoluteAtomIvars[0],
75 _absoluteAtomIvars.size()
76 * sizeof(NativeAbsoluteAtomIvarsV1));
77 }
78
Nick Kledzik49d6cc82012-02-15 00:38:09 +000079 if (!_stringPool.empty()) {
80 assert( out.tell() == findChunk(NCS_Strings).fileOffset );
Michael J. Spencer8c36f452012-01-31 21:46:41 +000081 out.write(&_stringPool[0], _stringPool.size());
Nick Kledzik49d6cc82012-02-15 00:38:09 +000082 }
83
84 if ( !_references.empty() ) {
85 assert( out.tell() == findChunk(NCS_ReferencesArrayV1).fileOffset );
86 out.write((char*)&_references[0],
87 _references.size()*sizeof(NativeReferenceIvarsV1));
88 }
89
90 if ( !_targetsTableIndex.empty() ) {
91 assert( out.tell() == findChunk(NCS_TargetsTable).fileOffset );
92 writeTargetTable(out);
93 }
94
95 if ( !_addendsTableIndex.empty() ) {
96 assert( out.tell() == findChunk(NCS_AddendsTable).fileOffset );
97 writeAddendTable(out);
98 }
99
100 if (!_contentPool.empty()) {
101 assert( out.tell() == findChunk(NCS_Content).fileOffset );
Nick Kledzik23384e82012-02-07 02:59:54 +0000102 out.write((char*)&_contentPool[0], _contentPool.size());
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000103 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000104 }
105
106private:
107
108 // visitor routine called by forEachAtom()
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000109 virtual void doDefinedAtom(const DefinedAtom& atom) {
110 _definedAtomIndex[&atom] = _definedAtomIvars.size();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000111 NativeDefinedAtomIvarsV1 ivar;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000112 unsigned refsCount;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000113 ivar.nameOffset = getNameOffset(atom);
114 ivar.attributesOffset = getAttributeOffset(atom);
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000115 ivar.referencesStartIndex = getReferencesIndex(atom, refsCount);
116 ivar.referencesCount = refsCount;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000117 ivar.contentOffset = getContentOffset(atom);
118 ivar.contentSize = atom.size();
119 _definedAtomIvars.push_back(ivar);
120 }
121
122 // visitor routine called by forEachAtom()
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000123 virtual void doUndefinedAtom(const UndefinedAtom& atom) {
124 _undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
Nick Kledzik23384e82012-02-07 02:59:54 +0000125 NativeUndefinedAtomIvarsV1 ivar;
126 ivar.nameOffset = getNameOffset(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000127 ivar.flags = (atom.canBeNull() & 0x03);
Nick Kledzik23384e82012-02-07 02:59:54 +0000128 _undefinedAtomIvars.push_back(ivar);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000129 }
130
131 // visitor routine called by forEachAtom()
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000132 virtual void doSharedLibraryAtom(const SharedLibraryAtom& atom) {
133 _sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
134 NativeSharedLibraryAtomIvarsV1 ivar;
135 ivar.nameOffset = getNameOffset(atom);
136 ivar.loadNameOffset = getSharedLibraryNameOffset(atom.loadName());
137 ivar.flags = atom.canBeNullAtRuntime();
138 _sharedLibraryAtomIvars.push_back(ivar);
139 }
140
141 // visitor routine called by forEachAtom()
142 virtual void doAbsoluteAtom(const AbsoluteAtom& atom) {
143 _absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
144 NativeAbsoluteAtomIvarsV1 ivar;
145 ivar.nameOffset = getNameOffset(atom);
146 ivar.reserved = 0;
147 ivar.value = atom.value();
148 _absoluteAtomIvars.push_back(ivar);
149 }
150
151 // visitor routine called by forEachAtom()
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000152 virtual void doFile(const File &) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000153 }
Nick Kledzik23384e82012-02-07 02:59:54 +0000154
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000155 // fill out native file header and chunk directory
156 void makeHeader() {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000157 const bool hasDefines = !_definedAtomIvars.empty();
Nick Kledzik23384e82012-02-07 02:59:54 +0000158 const bool hasUndefines = !_undefinedAtomIvars.empty();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000159 const bool hasSharedLibraries = !_sharedLibraryAtomIvars.empty();
160 const bool hasAbsolutes = !_absoluteAtomIvars.empty();
161 const bool hasReferences = !_references.empty();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000162 const bool hasTargetsTable = !_targetsTableIndex.empty();
163 const bool hasAddendTable = !_addendsTableIndex.empty();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000164 const bool hasContent = !_contentPool.empty();
165
166 int chunkCount = 1; // always have string pool chunk
167 if ( hasDefines ) chunkCount += 2;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000168 if ( hasUndefines ) ++chunkCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000169 if ( hasSharedLibraries ) ++chunkCount;
170 if ( hasAbsolutes ) ++chunkCount;
171 if ( hasReferences ) ++chunkCount;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000172 if ( hasTargetsTable ) ++chunkCount;
173 if ( hasAddendTable ) ++chunkCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000174 if ( hasContent ) ++chunkCount;
175
Nick Kledzik23384e82012-02-07 02:59:54 +0000176 _headerBufferSize = sizeof(NativeFileHeader)
177 + chunkCount*sizeof(NativeChunk);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000178 _headerBuffer = reinterpret_cast<NativeFileHeader*>
179 (operator new(_headerBufferSize, std::nothrow));
Michael J. Spencerb2bd7332012-01-31 21:45:53 +0000180 NativeChunk *chunks =
181 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
182 + sizeof(NativeFileHeader));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000183 memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC, 16);
184 _headerBuffer->endian = NFH_LittleEndian;
185 _headerBuffer->architecture = 0;
186 _headerBuffer->fileSize = 0;
Nick Kledzik23384e82012-02-07 02:59:54 +0000187 _headerBuffer->chunkCount = chunkCount;
188
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000189 // create chunk for defined atom ivar array
Nick Kledzik23384e82012-02-07 02:59:54 +0000190 int nextIndex = 0;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000191 uint32_t nextFileOffset = _headerBufferSize;
192 if ( hasDefines ) {
193 NativeChunk& chd = chunks[nextIndex++];
194 chd.signature = NCS_DefinedAtomsV1;
195 chd.fileOffset = nextFileOffset;
196 chd.fileSize = _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1);
197 chd.elementCount = _definedAtomIvars.size();
198 nextFileOffset = chd.fileOffset + chd.fileSize;
Nick Kledzik23384e82012-02-07 02:59:54 +0000199
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000200 // create chunk for attributes
201 NativeChunk& cha = chunks[nextIndex++];
202 cha.signature = NCS_AttributesArrayV1;
203 cha.fileOffset = nextFileOffset;
204 cha.fileSize = _attributes.size()*sizeof(NativeAtomAttributesV1);
205 cha.elementCount = _attributes.size();
206 nextFileOffset = cha.fileOffset + cha.fileSize;
207 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000208
Nick Kledzik23384e82012-02-07 02:59:54 +0000209 // create chunk for undefined atom array
210 if ( hasUndefines ) {
211 NativeChunk& chu = chunks[nextIndex++];
212 chu.signature = NCS_UndefinedAtomsV1;
213 chu.fileOffset = nextFileOffset;
214 chu.fileSize = _undefinedAtomIvars.size() *
215 sizeof(NativeUndefinedAtomIvarsV1);
216 chu.elementCount = _undefinedAtomIvars.size();
217 nextFileOffset = chu.fileOffset + chu.fileSize;
218 }
219
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000220 // create chunk for shared library atom array
221 if ( hasSharedLibraries ) {
222 NativeChunk& chsl = chunks[nextIndex++];
223 chsl.signature = NCS_SharedLibraryAtomsV1;
224 chsl.fileOffset = nextFileOffset;
225 chsl.fileSize = _sharedLibraryAtomIvars.size() *
226 sizeof(NativeSharedLibraryAtomIvarsV1);
227 chsl.elementCount = _sharedLibraryAtomIvars.size();
228 nextFileOffset = chsl.fileOffset + chsl.fileSize;
229 }
230
231 // create chunk for shared library atom array
232 if ( hasAbsolutes ) {
233 NativeChunk& chsl = chunks[nextIndex++];
234 chsl.signature = NCS_AbsoluteAtomsV1;
235 chsl.fileOffset = nextFileOffset;
236 chsl.fileSize = _absoluteAtomIvars.size() *
237 sizeof(NativeAbsoluteAtomIvarsV1);
238 chsl.elementCount = _absoluteAtomIvars.size();
239 nextFileOffset = chsl.fileOffset + chsl.fileSize;
240 }
241
Nick Kledzik23384e82012-02-07 02:59:54 +0000242 // create chunk for symbol strings
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000243 // pad end of string pool to 4-bytes
244 while ( (_stringPool.size() % 4) != 0 )
245 _stringPool.push_back('\0');
Nick Kledzik23384e82012-02-07 02:59:54 +0000246 NativeChunk& chs = chunks[nextIndex++];
247 chs.signature = NCS_Strings;
248 chs.fileOffset = nextFileOffset;
249 chs.fileSize = _stringPool.size();
250 chs.elementCount = _stringPool.size();
251 nextFileOffset = chs.fileOffset + chs.fileSize;
252
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000253 // create chunk for references
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000254 if ( hasReferences ) {
255 NativeChunk& chr = chunks[nextIndex++];
256 chr.signature = NCS_ReferencesArrayV1;
257 chr.fileOffset = nextFileOffset;
258 chr.fileSize = _references.size() * sizeof(NativeReferenceIvarsV1);
259 chr.elementCount = _references.size();
260 nextFileOffset = chr.fileOffset + chr.fileSize;
261 }
262
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000263 // create chunk for target table
264 if ( hasTargetsTable ) {
265 NativeChunk& cht = chunks[nextIndex++];
266 cht.signature = NCS_TargetsTable;
267 cht.fileOffset = nextFileOffset;
268 cht.fileSize = _targetsTableIndex.size() * sizeof(uint32_t);
269 cht.elementCount = _targetsTableIndex.size();
270 nextFileOffset = cht.fileOffset + cht.fileSize;
271 }
272
273 // create chunk for addend table
274 if ( hasAddendTable ) {
275 NativeChunk& chad = chunks[nextIndex++];
276 chad.signature = NCS_AddendsTable;
277 chad.fileOffset = nextFileOffset;
278 chad.fileSize = _addendsTableIndex.size() * sizeof(Reference::Addend);
279 chad.elementCount = _addendsTableIndex.size();
280 nextFileOffset = chad.fileOffset + chad.fileSize;
281 }
282
Nick Kledzik23384e82012-02-07 02:59:54 +0000283 // create chunk for content
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000284 if ( hasContent ) {
285 NativeChunk& chc = chunks[nextIndex++];
286 chc.signature = NCS_Content;
287 chc.fileOffset = nextFileOffset;
288 chc.fileSize = _contentPool.size();
289 chc.elementCount = _contentPool.size();
290 nextFileOffset = chc.fileOffset + chc.fileSize;
291 }
292
Nick Kledzik23384e82012-02-07 02:59:54 +0000293 _headerBuffer->fileSize = nextFileOffset;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000294 }
295
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000296 // scan header to find particular chunk
297 NativeChunk& findChunk(uint32_t signature) {
298 const uint32_t chunkCount = _headerBuffer->chunkCount;
299 NativeChunk* chunks =
300 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
301 + sizeof(NativeFileHeader));
302 for (uint32_t i=0; i < chunkCount; ++i) {
303 if ( chunks[i].signature == signature )
304 return chunks[i];
305 }
306 assert(0 && "findChunk() signature not found");
307 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000308
309 // append atom name to string pool and return offset
Nick Kledzik23384e82012-02-07 02:59:54 +0000310 uint32_t getNameOffset(const Atom& atom) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000311 return this->getNameOffset(atom.name());
312 }
313
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000314 // check if name is already in pool or append and return offset
315 uint32_t getSharedLibraryNameOffset(llvm::StringRef name) {
316 assert( ! name.empty() );
317 // look to see if this library name was used by another atom
318 for(NameToOffsetVector::iterator it = _sharedLibraryNames.begin();
319 it != _sharedLibraryNames.end(); ++it) {
320 if ( name.equals(it->first) )
321 return it->second;
322 }
323 // first use of this library name
324 uint32_t result = this->getNameOffset(name);
325 _sharedLibraryNames.push_back(
326 std::make_pair<llvm::StringRef, uint32_t>(name, result));
327 return result;
328 }
329
330 // append atom name to string pool and return offset
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000331 uint32_t getNameOffset(llvm::StringRef name) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000332 if ( name.empty() )
333 return 0;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000334 uint32_t result = _stringPool.size();
335 _stringPool.insert(_stringPool.end(), name.size()+1, 0);
336 strcpy(&_stringPool[result], name.data());
337 return result;
338 }
339
340 // append atom cotent to content pool and return offset
341 uint32_t getContentOffset(const class DefinedAtom& atom) {
342 if ( atom.contentType() == DefinedAtom::typeZeroFill )
343 return 0;
344 uint32_t result = _contentPool.size();
345 llvm::ArrayRef<uint8_t> cont = atom.rawContent();
Michael J. Spencer846fe662012-01-31 21:46:05 +0000346 _contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000347 return result;
348 }
349
350 // reuse existing attributes entry or create a new one and return offet
351 uint32_t getAttributeOffset(const class DefinedAtom& atom) {
352 NativeAtomAttributesV1 attrs;
353 computeAttributesV1(atom, attrs);
354 for(unsigned int i=0; i < _attributes.size(); ++i) {
355 if ( !memcmp(&_attributes[i], &attrs, sizeof(NativeAtomAttributesV1)) ) {
356 // found that this set of attributes already used, so re-use
357 return i * sizeof(NativeAtomAttributesV1);
358 }
359 }
360 // append new attribute set to end
361 uint32_t result = _attributes.size() * sizeof(NativeAtomAttributesV1);
362 _attributes.push_back(attrs);
363 return result;
364 }
365
366 uint32_t sectionNameOffset(const class DefinedAtom& atom) {
367 // if section based on content, then no custom section name available
368 if ( atom.sectionChoice() == DefinedAtom::sectionBasedOnContent )
369 return 0;
370 llvm::StringRef name = atom.customSectionName();
371 assert( ! name.empty() );
372 // look to see if this section name was used by another atom
373 for(NameToOffsetVector::iterator it=_sectionNames.begin();
374 it != _sectionNames.end(); ++it) {
375 if ( name.equals(it->first) )
376 return it->second;
377 }
378 // first use of this section name
379 uint32_t result = this->getNameOffset(name);
380 _sectionNames.push_back(
381 std::make_pair<llvm::StringRef, uint32_t>(name, result));
382 return result;
383 }
384
385 void computeAttributesV1(const class DefinedAtom& atom,
386 NativeAtomAttributesV1& attrs) {
387 attrs.sectionNameOffset = sectionNameOffset(atom);
388 attrs.align2 = atom.alignment().powerOf2;
389 attrs.alignModulus = atom.alignment().modulus;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000390 attrs.scope = atom.scope();
391 attrs.interposable = atom.interposable();
392 attrs.merge = atom.merge();
393 attrs.contentType = atom.contentType();
394 attrs.sectionChoice = atom.sectionChoice();
395 attrs.deadStrip = atom.deadStrip();
396 attrs.permissions = atom.permissions();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000397 //attrs.thumb = atom.isThumb();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000398 attrs.alias = atom.isAlias();
399 }
400
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000401 // add references for this atom in a contiguous block in NCS_ReferencesArrayV1
402 uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& count) {
403 count = 0;
404 size_t startRefSize = _references.size();
405 uint32_t result = startRefSize;
406 atom.forEachReference(*this);
407 count = _references.size() - startRefSize;
408 if ( count == 0 )
409 return 0;
410 else
411 return result;
412 }
413
414 void doReference(const Reference& ref) {
415 NativeReferenceIvarsV1 nref;
416 nref.offsetInAtom = ref.offsetInAtom();
417 nref.kind = ref.kind();
418 nref.targetIndex = this->getTargetIndex(ref.target());
419 nref.addendIndex = this->getAddendIndex(ref.addend());
420 _references.push_back(nref);
421 }
422
423 uint32_t getTargetIndex(const Atom* target) {
424 TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
425 if ( pos != _targetsTableIndex.end() ) {
426 return pos->second;
427 }
428 uint32_t result = _targetsTableIndex.size();
429 _targetsTableIndex[target] = result;
430 return result;
431 }
432
433 void writeTargetTable(llvm::raw_ostream& out) {
434 // Build table of target indexes
435 uint32_t maxTargetIndex = _targetsTableIndex.size();
436 uint32_t targetIndexes[maxTargetIndex];
437 for (TargetToIndex::iterator it = _targetsTableIndex.begin();
438 it != _targetsTableIndex.end(); ++it) {
439 const Atom* atom = it->first;
440 uint32_t targetIndex = it->second;
441 assert(targetIndex < maxTargetIndex);
442 uint32_t atomIndex = 0;
443 TargetToIndex::iterator pos = _definedAtomIndex.find(atom);
444 if ( pos != _definedAtomIndex.end() ) {
445 atomIndex = pos->second;
446 }
447 else {
448 pos = _undefinedAtomIndex.find(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000449 if ( pos != _undefinedAtomIndex.end() ) {
450 atomIndex = pos->second + _definedAtomIvars.size();
451 }
452 else {
453 pos = _sharedLibraryAtomIndex.find(atom);
454 if ( pos != _sharedLibraryAtomIndex.end() ) {
455 assert(pos != _sharedLibraryAtomIndex.end());
456 atomIndex = pos->second
457 + _definedAtomIvars.size()
458 + _undefinedAtomIndex.size();
459 }
460 else {
461 pos = _absoluteAtomIndex.find(atom);
462 assert(pos != _absoluteAtomIndex.end());
463 atomIndex = pos->second
464 + _definedAtomIvars.size()
465 + _undefinedAtomIndex.size()
466 + _sharedLibraryAtomIndex.size();
467 }
468 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000469 }
470 targetIndexes[targetIndex] = atomIndex;
471 }
472 // write table
473 out.write((char*)&targetIndexes[0], maxTargetIndex*sizeof(uint32_t));
474 }
475
476 uint32_t getAddendIndex(Reference::Addend addend) {
477 if ( addend == 0 )
478 return 0; // addend index zero is used to mean "no addend"
479 AddendToIndex::const_iterator pos = _addendsTableIndex.find(addend);
480 if ( pos != _addendsTableIndex.end() ) {
481 return pos->second;
482 }
483 uint32_t result = _addendsTableIndex.size() + 1; // one-based index
484 _addendsTableIndex[addend] = result;
485 return result;
486 }
487
488 void writeAddendTable(llvm::raw_ostream& out) {
489 // Build table of addends
490 uint32_t maxAddendIndex = _addendsTableIndex.size();
491 Reference::Addend addends[maxAddendIndex];
492 for (AddendToIndex::iterator it = _addendsTableIndex.begin();
493 it != _addendsTableIndex.end(); ++it) {
494 Reference::Addend addend = it->first;
495 uint32_t index = it->second;
496 assert(index <= maxAddendIndex);
497 addends[index-1] = addend;
498 }
499 // write table
500 out.write((char*)&addends[0], maxAddendIndex*sizeof(Reference::Addend));
501 }
502
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000503 typedef std::vector<std::pair<llvm::StringRef, uint32_t> > NameToOffsetVector;
504
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000505 typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex;
506 typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex;
507
Nick Kledzik23384e82012-02-07 02:59:54 +0000508 const lld::File& _file;
509 NativeFileHeader* _headerBuffer;
510 size_t _headerBufferSize;
511 std::vector<char> _stringPool;
512 std::vector<uint8_t> _contentPool;
513 std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
514 std::vector<NativeAtomAttributesV1> _attributes;
515 std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000516 std::vector<NativeSharedLibraryAtomIvarsV1> _sharedLibraryAtomIvars;
517 std::vector<NativeAbsoluteAtomIvarsV1> _absoluteAtomIvars;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000518 std::vector<NativeReferenceIvarsV1> _references;
519 TargetToIndex _targetsTableIndex;
520 TargetToIndex _definedAtomIndex;
521 TargetToIndex _undefinedAtomIndex;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000522 TargetToIndex _sharedLibraryAtomIndex;
523 TargetToIndex _absoluteAtomIndex;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000524 AddendToIndex _addendsTableIndex;
Nick Kledzik23384e82012-02-07 02:59:54 +0000525 NameToOffsetVector _sectionNames;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000526 NameToOffsetVector _sharedLibraryNames;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000527};
528
529
530
531
532
533/// writeNativeObjectFile - writes the lld::File object in native object
534/// file format to the specified stream.
535int writeNativeObjectFile(const lld::File &file, llvm::raw_ostream &out) {
536 NativeWriter writer(file);
537 writer.write(out);
538 return 0;
539}
540
541/// writeNativeObjectFile - writes the lld::File object in native object
542/// file format to the specified file path.
543int writeNativeObjectFile(const lld::File& file, llvm::StringRef path) {
544 std::string errorInfo;
545 llvm::raw_fd_ostream out(path.data(), errorInfo, llvm::raw_fd_ostream::F_Binary);
546 if ( !errorInfo.empty() )
547 return -1;
548 return writeNativeObjectFile(file, out);
549}
550
551} // namespace lld