blob: 4415ed886993674cba2eea0210f747bc446b88c7 [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);
338 _sharedLibraryNames.push_back(
339 std::make_pair<llvm::StringRef, uint32_t>(name, result));
340 return result;
341 }
342
343 // append atom name to string pool and return offset
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000344 uint32_t getNameOffset(llvm::StringRef name) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000345 if ( name.empty() )
346 return 0;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000347 uint32_t result = _stringPool.size();
348 _stringPool.insert(_stringPool.end(), name.size()+1, 0);
349 strcpy(&_stringPool[result], name.data());
350 return result;
351 }
352
353 // append atom cotent to content pool and return offset
354 uint32_t getContentOffset(const class DefinedAtom& atom) {
355 if ( atom.contentType() == DefinedAtom::typeZeroFill )
356 return 0;
357 uint32_t result = _contentPool.size();
358 llvm::ArrayRef<uint8_t> cont = atom.rawContent();
Michael J. Spencer846fe662012-01-31 21:46:05 +0000359 _contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000360 return result;
361 }
362
363 // reuse existing attributes entry or create a new one and return offet
364 uint32_t getAttributeOffset(const class DefinedAtom& atom) {
365 NativeAtomAttributesV1 attrs;
366 computeAttributesV1(atom, attrs);
367 for(unsigned int i=0; i < _attributes.size(); ++i) {
368 if ( !memcmp(&_attributes[i], &attrs, sizeof(NativeAtomAttributesV1)) ) {
369 // found that this set of attributes already used, so re-use
370 return i * sizeof(NativeAtomAttributesV1);
371 }
372 }
373 // append new attribute set to end
374 uint32_t result = _attributes.size() * sizeof(NativeAtomAttributesV1);
375 _attributes.push_back(attrs);
376 return result;
377 }
378
379 uint32_t sectionNameOffset(const class DefinedAtom& atom) {
380 // if section based on content, then no custom section name available
381 if ( atom.sectionChoice() == DefinedAtom::sectionBasedOnContent )
382 return 0;
383 llvm::StringRef name = atom.customSectionName();
384 assert( ! name.empty() );
385 // look to see if this section name was used by another atom
386 for(NameToOffsetVector::iterator it=_sectionNames.begin();
387 it != _sectionNames.end(); ++it) {
388 if ( name.equals(it->first) )
389 return it->second;
390 }
391 // first use of this section name
392 uint32_t result = this->getNameOffset(name);
393 _sectionNames.push_back(
394 std::make_pair<llvm::StringRef, uint32_t>(name, result));
395 return result;
396 }
397
398 void computeAttributesV1(const class DefinedAtom& atom,
399 NativeAtomAttributesV1& attrs) {
400 attrs.sectionNameOffset = sectionNameOffset(atom);
401 attrs.align2 = atom.alignment().powerOf2;
402 attrs.alignModulus = atom.alignment().modulus;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000403 attrs.scope = atom.scope();
404 attrs.interposable = atom.interposable();
405 attrs.merge = atom.merge();
406 attrs.contentType = atom.contentType();
407 attrs.sectionChoice = atom.sectionChoice();
408 attrs.deadStrip = atom.deadStrip();
409 attrs.permissions = atom.permissions();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000410 //attrs.thumb = atom.isThumb();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000411 attrs.alias = atom.isAlias();
412 }
413
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000414 // add references for this atom in a contiguous block in NCS_ReferencesArrayV1
415 uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& count) {
416 count = 0;
417 size_t startRefSize = _references.size();
418 uint32_t result = startRefSize;
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000419 for (auto it=atom.referencesBegin(), end=atom.referencesEnd();
420 it != end; ++it) {
421 const Reference* ref = *it;
422 NativeReferenceIvarsV1 nref;
423 nref.offsetInAtom = ref->offsetInAtom();
424 nref.kind = ref->kind();
425 nref.targetIndex = this->getTargetIndex(ref->target());
426 nref.addendIndex = this->getAddendIndex(ref->addend());
427 _references.push_back(nref);
428 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000429 count = _references.size() - startRefSize;
430 if ( count == 0 )
431 return 0;
432 else
433 return result;
434 }
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000435
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000436 uint32_t getTargetIndex(const Atom* target) {
437 TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
438 if ( pos != _targetsTableIndex.end() ) {
439 return pos->second;
440 }
441 uint32_t result = _targetsTableIndex.size();
442 _targetsTableIndex[target] = result;
443 return result;
444 }
445
446 void writeTargetTable(llvm::raw_ostream& out) {
447 // Build table of target indexes
448 uint32_t maxTargetIndex = _targetsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000449 assert(maxTargetIndex > 0);
450 std::vector<uint32_t> targetIndexes(maxTargetIndex);
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000451 for (TargetToIndex::iterator it = _targetsTableIndex.begin();
452 it != _targetsTableIndex.end(); ++it) {
453 const Atom* atom = it->first;
454 uint32_t targetIndex = it->second;
455 assert(targetIndex < maxTargetIndex);
456 uint32_t atomIndex = 0;
457 TargetToIndex::iterator pos = _definedAtomIndex.find(atom);
458 if ( pos != _definedAtomIndex.end() ) {
459 atomIndex = pos->second;
460 }
461 else {
462 pos = _undefinedAtomIndex.find(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000463 if ( pos != _undefinedAtomIndex.end() ) {
464 atomIndex = pos->second + _definedAtomIvars.size();
465 }
466 else {
467 pos = _sharedLibraryAtomIndex.find(atom);
468 if ( pos != _sharedLibraryAtomIndex.end() ) {
469 assert(pos != _sharedLibraryAtomIndex.end());
470 atomIndex = pos->second
471 + _definedAtomIvars.size()
472 + _undefinedAtomIndex.size();
473 }
474 else {
475 pos = _absoluteAtomIndex.find(atom);
476 assert(pos != _absoluteAtomIndex.end());
477 atomIndex = pos->second
478 + _definedAtomIvars.size()
479 + _undefinedAtomIndex.size()
480 + _sharedLibraryAtomIndex.size();
481 }
482 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000483 }
484 targetIndexes[targetIndex] = atomIndex;
485 }
486 // write table
487 out.write((char*)&targetIndexes[0], maxTargetIndex*sizeof(uint32_t));
488 }
489
490 uint32_t getAddendIndex(Reference::Addend addend) {
491 if ( addend == 0 )
492 return 0; // addend index zero is used to mean "no addend"
493 AddendToIndex::const_iterator pos = _addendsTableIndex.find(addend);
494 if ( pos != _addendsTableIndex.end() ) {
495 return pos->second;
496 }
497 uint32_t result = _addendsTableIndex.size() + 1; // one-based index
498 _addendsTableIndex[addend] = result;
499 return result;
500 }
501
502 void writeAddendTable(llvm::raw_ostream& out) {
503 // Build table of addends
504 uint32_t maxAddendIndex = _addendsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000505 std::vector<Reference::Addend> addends(maxAddendIndex);
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000506 for (AddendToIndex::iterator it = _addendsTableIndex.begin();
507 it != _addendsTableIndex.end(); ++it) {
508 Reference::Addend addend = it->first;
509 uint32_t index = it->second;
510 assert(index <= maxAddendIndex);
511 addends[index-1] = addend;
512 }
513 // write table
514 out.write((char*)&addends[0], maxAddendIndex*sizeof(Reference::Addend));
515 }
516
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000517 typedef std::vector<std::pair<llvm::StringRef, uint32_t> > NameToOffsetVector;
518
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000519 typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex;
520 typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex;
521
Nick Kledzik23384e82012-02-07 02:59:54 +0000522 const lld::File& _file;
523 NativeFileHeader* _headerBuffer;
524 size_t _headerBufferSize;
525 std::vector<char> _stringPool;
526 std::vector<uint8_t> _contentPool;
527 std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
528 std::vector<NativeAtomAttributesV1> _attributes;
529 std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000530 std::vector<NativeSharedLibraryAtomIvarsV1> _sharedLibraryAtomIvars;
531 std::vector<NativeAbsoluteAtomIvarsV1> _absoluteAtomIvars;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000532 std::vector<NativeReferenceIvarsV1> _references;
533 TargetToIndex _targetsTableIndex;
534 TargetToIndex _definedAtomIndex;
535 TargetToIndex _undefinedAtomIndex;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000536 TargetToIndex _sharedLibraryAtomIndex;
537 TargetToIndex _absoluteAtomIndex;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000538 AddendToIndex _addendsTableIndex;
Nick Kledzik23384e82012-02-07 02:59:54 +0000539 NameToOffsetVector _sectionNames;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000540 NameToOffsetVector _sharedLibraryNames;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000541};
542
543
544
545
546
547/// writeNativeObjectFile - writes the lld::File object in native object
548/// file format to the specified stream.
549int writeNativeObjectFile(const lld::File &file, llvm::raw_ostream &out) {
550 NativeWriter writer(file);
551 writer.write(out);
552 return 0;
553}
554
555/// writeNativeObjectFile - writes the lld::File object in native object
556/// file format to the specified file path.
557int writeNativeObjectFile(const lld::File& file, llvm::StringRef path) {
558 std::string errorInfo;
559 llvm::raw_fd_ostream out(path.data(), errorInfo, llvm::raw_fd_ostream::F_Binary);
560 if ( !errorInfo.empty() )
561 return -1;
562 return writeNativeObjectFile(file, out);
563}
564
565} // namespace lld