blob: 09e0d9a267ed2a89e6b9464012f59bea872bdd11 [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
Michael J. Spencercfd029f2012-03-28 19:04:02 +000010#include "lld/Core/NativeWriter.h"
11#include "NativeFileFormat.h"
12#include "lld/Core/File.h"
Nick Kledzik55fd6be2012-01-16 22:03:44 +000013
Nick Kledzik55fd6be2012-01-16 22:03:44 +000014#include "llvm/ADT/ArrayRef.h"
Nick Kledzik49d6cc82012-02-15 00:38:09 +000015#include "llvm/ADT/DenseMap.h"
Michael J. Spencercfd029f2012-03-28 19:04:02 +000016#include "llvm/ADT/StringRef.h"
Nick Kledzik55fd6be2012-01-16 22:03:44 +000017
Michael J. Spencercfd029f2012-03-28 19:04:02 +000018#include <vector>
Nick Kledzik55fd6be2012-01-16 22:03:44 +000019
20namespace lld {
21
22
23///
24/// Class for writing native object files.
25///
Nick Kledzik1a6615d2012-03-08 00:18:30 +000026class NativeWriter {
Nick Kledzik55fd6be2012-01-16 22:03:44 +000027public:
28 /// construct writer for an lld::File object
Michael J. Spencer765792d2012-04-03 18:40:27 +000029 NativeWriter(const lld::File& file) : _file(file) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +000030 // reserve first byte for unnamed atoms
31 _stringPool.push_back('\0');
Nick Kledzik55fd6be2012-01-16 22:03:44 +000032 // visit all atoms
Michael J. Spencer765792d2012-04-03 18:40:27 +000033 for(File::defined_iterator it=file.definedAtomsBegin(),
34 end=file.definedAtomsEnd();
Nick Kledzik1a6615d2012-03-08 00:18:30 +000035 it != end; ++it) {
36 this->addIVarsForDefinedAtom(**it);
37 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000038 for(File::undefined_iterator it=file.undefinedAtomsBegin(),
39 end=file.undefinedAtomsEnd();
Nick Kledzik1a6615d2012-03-08 00:18:30 +000040 it != end; ++it) {
41 this->addIVarsForUndefinedAtom(**it);
42 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000043 for(File::shared_library_iterator it=file.sharedLibraryAtomsBegin(),
44 end=file.sharedLibraryAtomsEnd();
Nick Kledzik1a6615d2012-03-08 00:18:30 +000045 it != end; ++it) {
46 this->addIVarsForSharedLibraryAtom(**it);
47 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000048 for(File::absolute_iterator it=file.absoluteAtomsBegin(),
49 end=file.absoluteAtomsEnd();
Nick Kledzik1a6615d2012-03-08 00:18:30 +000050 it != end; ++it) {
51 this->addIVarsForAbsoluteAtom(**it);
52 }
53
Michael J. Spencer765792d2012-04-03 18:40:27 +000054
55
Nick Kledzik55fd6be2012-01-16 22:03:44 +000056 // construct file header based on atom information accumulated
57 makeHeader();
58 }
59
60 // write the lld::File in native format to the specified stream
Michael J. Spencere6203a52012-04-03 18:39:40 +000061 void write(raw_ostream &out) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +000062 assert( out.tell() == 0 );
Nick Kledzik55fd6be2012-01-16 22:03:44 +000063 out.write((char*)_headerBuffer, _headerBufferSize);
Michael J. Spencer765792d2012-04-03 18:40:27 +000064
Nick Kledzik49d6cc82012-02-15 00:38:09 +000065 if (!_definedAtomIvars.empty()) {
66 assert( out.tell() == findChunk(NCS_DefinedAtomsV1).fileOffset );
Michael J. Spencer8c36f452012-01-31 21:46:41 +000067 out.write((char*)&_definedAtomIvars[0],
68 _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1));
Nick Kledzik49d6cc82012-02-15 00:38:09 +000069 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000070
Nick Kledzik49d6cc82012-02-15 00:38:09 +000071 if (!_attributes.empty()) {
72 assert( out.tell() == findChunk(NCS_AttributesArrayV1).fileOffset );
Michael J. Spencer8c36f452012-01-31 21:46:41 +000073 out.write((char*)&_attributes[0],
74 _attributes.size()*sizeof(NativeAtomAttributesV1));
Nick Kledzik49d6cc82012-02-15 00:38:09 +000075 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000076
Nick Kledzik49d6cc82012-02-15 00:38:09 +000077 if ( !_undefinedAtomIvars.empty() ) {
78 assert( out.tell() == findChunk(NCS_UndefinedAtomsV1).fileOffset );
Michael J. Spencer765792d2012-04-03 18:40:27 +000079 out.write((char*)&_undefinedAtomIvars[0],
Nick Kledzik23384e82012-02-07 02:59:54 +000080 _undefinedAtomIvars.size()*sizeof(NativeUndefinedAtomIvarsV1));
Nick Kledzik49d6cc82012-02-15 00:38:09 +000081 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000082
Nick Kledzik6bc04c62012-02-22 21:56:59 +000083 if ( !_sharedLibraryAtomIvars.empty() ) {
84 assert( out.tell() == findChunk(NCS_SharedLibraryAtomsV1).fileOffset );
Michael J. Spencer765792d2012-04-03 18:40:27 +000085 out.write((char*)&_sharedLibraryAtomIvars[0],
86 _sharedLibraryAtomIvars.size()
Nick Kledzik6bc04c62012-02-22 21:56:59 +000087 * sizeof(NativeSharedLibraryAtomIvarsV1));
88 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000089
Nick Kledzik6bc04c62012-02-22 21:56:59 +000090 if ( !_absoluteAtomIvars.empty() ) {
91 assert( out.tell() == findChunk(NCS_AbsoluteAtomsV1).fileOffset );
Michael J. Spencer765792d2012-04-03 18:40:27 +000092 out.write((char*)&_absoluteAtomIvars[0],
93 _absoluteAtomIvars.size()
Nick Kledzik6bc04c62012-02-22 21:56:59 +000094 * sizeof(NativeAbsoluteAtomIvarsV1));
95 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000096
Nick Kledzik49d6cc82012-02-15 00:38:09 +000097 if (!_stringPool.empty()) {
98 assert( out.tell() == findChunk(NCS_Strings).fileOffset );
Michael J. Spencer8c36f452012-01-31 21:46:41 +000099 out.write(&_stringPool[0], _stringPool.size());
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000100 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000101
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000102 if ( !_references.empty() ) {
103 assert( out.tell() == findChunk(NCS_ReferencesArrayV1).fileOffset );
Michael J. Spencer765792d2012-04-03 18:40:27 +0000104 out.write((char*)&_references[0],
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000105 _references.size()*sizeof(NativeReferenceIvarsV1));
106 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000107
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000108 if ( !_targetsTableIndex.empty() ) {
109 assert( out.tell() == findChunk(NCS_TargetsTable).fileOffset );
110 writeTargetTable(out);
111 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000112
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000113 if ( !_addendsTableIndex.empty() ) {
114 assert( out.tell() == findChunk(NCS_AddendsTable).fileOffset );
115 writeAddendTable(out);
116 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000117
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000118 if (!_contentPool.empty()) {
119 assert( out.tell() == findChunk(NCS_Content).fileOffset );
Nick Kledzik23384e82012-02-07 02:59:54 +0000120 out.write((char*)&_contentPool[0], _contentPool.size());
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000121 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000122 }
123
124private:
125
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000126 void addIVarsForDefinedAtom(const DefinedAtom& atom) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000127 _definedAtomIndex[&atom] = _definedAtomIvars.size();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000128 NativeDefinedAtomIvarsV1 ivar;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000129 unsigned refsCount;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000130 ivar.nameOffset = getNameOffset(atom);
131 ivar.attributesOffset = getAttributeOffset(atom);
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000132 ivar.referencesStartIndex = getReferencesIndex(atom, refsCount);
133 ivar.referencesCount = refsCount;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000134 ivar.contentOffset = getContentOffset(atom);
135 ivar.contentSize = atom.size();
136 _definedAtomIvars.push_back(ivar);
137 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000138
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000139 void addIVarsForUndefinedAtom(const UndefinedAtom& atom) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000140 _undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
Nick Kledzik23384e82012-02-07 02:59:54 +0000141 NativeUndefinedAtomIvarsV1 ivar;
142 ivar.nameOffset = getNameOffset(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000143 ivar.flags = (atom.canBeNull() & 0x03);
Nick Kledzik23384e82012-02-07 02:59:54 +0000144 _undefinedAtomIvars.push_back(ivar);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000145 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000146
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000147 void addIVarsForSharedLibraryAtom(const SharedLibraryAtom& atom) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000148 _sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
149 NativeSharedLibraryAtomIvarsV1 ivar;
150 ivar.nameOffset = getNameOffset(atom);
151 ivar.loadNameOffset = getSharedLibraryNameOffset(atom.loadName());
152 ivar.flags = atom.canBeNullAtRuntime();
153 _sharedLibraryAtomIvars.push_back(ivar);
154 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000155
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000156 void addIVarsForAbsoluteAtom(const AbsoluteAtom& atom) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000157 _absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
158 NativeAbsoluteAtomIvarsV1 ivar;
159 ivar.nameOffset = getNameOffset(atom);
160 ivar.reserved = 0;
161 ivar.value = atom.value();
162 _absoluteAtomIvars.push_back(ivar);
163 }
164
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000165 // fill out native file header and chunk directory
166 void makeHeader() {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000167 const bool hasDefines = !_definedAtomIvars.empty();
Nick Kledzik23384e82012-02-07 02:59:54 +0000168 const bool hasUndefines = !_undefinedAtomIvars.empty();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000169 const bool hasSharedLibraries = !_sharedLibraryAtomIvars.empty();
170 const bool hasAbsolutes = !_absoluteAtomIvars.empty();
171 const bool hasReferences = !_references.empty();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000172 const bool hasTargetsTable = !_targetsTableIndex.empty();
173 const bool hasAddendTable = !_addendsTableIndex.empty();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000174 const bool hasContent = !_contentPool.empty();
175
176 int chunkCount = 1; // always have string pool chunk
177 if ( hasDefines ) chunkCount += 2;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000178 if ( hasUndefines ) ++chunkCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000179 if ( hasSharedLibraries ) ++chunkCount;
180 if ( hasAbsolutes ) ++chunkCount;
181 if ( hasReferences ) ++chunkCount;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000182 if ( hasTargetsTable ) ++chunkCount;
183 if ( hasAddendTable ) ++chunkCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000184 if ( hasContent ) ++chunkCount;
185
Michael J. Spencer765792d2012-04-03 18:40:27 +0000186 _headerBufferSize = sizeof(NativeFileHeader)
Nick Kledzik23384e82012-02-07 02:59:54 +0000187 + chunkCount*sizeof(NativeChunk);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000188 _headerBuffer = reinterpret_cast<NativeFileHeader*>
189 (operator new(_headerBufferSize, std::nothrow));
Michael J. Spencerb2bd7332012-01-31 21:45:53 +0000190 NativeChunk *chunks =
191 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
192 + sizeof(NativeFileHeader));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000193 memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC, 16);
194 _headerBuffer->endian = NFH_LittleEndian;
195 _headerBuffer->architecture = 0;
196 _headerBuffer->fileSize = 0;
Nick Kledzik23384e82012-02-07 02:59:54 +0000197 _headerBuffer->chunkCount = chunkCount;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000198
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000199 // create chunk for defined atom ivar array
Nick Kledzik23384e82012-02-07 02:59:54 +0000200 int nextIndex = 0;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000201 uint32_t nextFileOffset = _headerBufferSize;
202 if ( hasDefines ) {
203 NativeChunk& chd = chunks[nextIndex++];
204 chd.signature = NCS_DefinedAtomsV1;
205 chd.fileOffset = nextFileOffset;
206 chd.fileSize = _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1);
207 chd.elementCount = _definedAtomIvars.size();
208 nextFileOffset = chd.fileOffset + chd.fileSize;
Nick Kledzik23384e82012-02-07 02:59:54 +0000209
Michael J. Spencer765792d2012-04-03 18:40:27 +0000210 // create chunk for attributes
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000211 NativeChunk& cha = chunks[nextIndex++];
212 cha.signature = NCS_AttributesArrayV1;
213 cha.fileOffset = nextFileOffset;
214 cha.fileSize = _attributes.size()*sizeof(NativeAtomAttributesV1);
215 cha.elementCount = _attributes.size();
216 nextFileOffset = cha.fileOffset + cha.fileSize;
217 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000218
Nick Kledzik23384e82012-02-07 02:59:54 +0000219 // create chunk for undefined atom array
220 if ( hasUndefines ) {
221 NativeChunk& chu = chunks[nextIndex++];
222 chu.signature = NCS_UndefinedAtomsV1;
223 chu.fileOffset = nextFileOffset;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000224 chu.fileSize = _undefinedAtomIvars.size() *
Nick Kledzik23384e82012-02-07 02:59:54 +0000225 sizeof(NativeUndefinedAtomIvarsV1);
226 chu.elementCount = _undefinedAtomIvars.size();
227 nextFileOffset = chu.fileOffset + chu.fileSize;
228 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000229
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000230 // create chunk for shared library atom array
231 if ( hasSharedLibraries ) {
232 NativeChunk& chsl = chunks[nextIndex++];
233 chsl.signature = NCS_SharedLibraryAtomsV1;
234 chsl.fileOffset = nextFileOffset;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000235 chsl.fileSize = _sharedLibraryAtomIvars.size() *
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000236 sizeof(NativeSharedLibraryAtomIvarsV1);
237 chsl.elementCount = _sharedLibraryAtomIvars.size();
238 nextFileOffset = chsl.fileOffset + chsl.fileSize;
239 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000240
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000241 // create chunk for shared library atom array
242 if ( hasAbsolutes ) {
243 NativeChunk& chsl = chunks[nextIndex++];
244 chsl.signature = NCS_AbsoluteAtomsV1;
245 chsl.fileOffset = nextFileOffset;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000246 chsl.fileSize = _absoluteAtomIvars.size() *
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000247 sizeof(NativeAbsoluteAtomIvarsV1);
248 chsl.elementCount = _absoluteAtomIvars.size();
249 nextFileOffset = chsl.fileOffset + chsl.fileSize;
250 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000251
Nick Kledzik23384e82012-02-07 02:59:54 +0000252 // create chunk for symbol strings
Michael J. Spencer765792d2012-04-03 18:40:27 +0000253 // pad end of string pool to 4-bytes
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000254 while ( (_stringPool.size() % 4) != 0 )
255 _stringPool.push_back('\0');
Nick Kledzik23384e82012-02-07 02:59:54 +0000256 NativeChunk& chs = chunks[nextIndex++];
257 chs.signature = NCS_Strings;
258 chs.fileOffset = nextFileOffset;
259 chs.fileSize = _stringPool.size();
260 chs.elementCount = _stringPool.size();
261 nextFileOffset = chs.fileOffset + chs.fileSize;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000262
263 // create chunk for references
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000264 if ( hasReferences ) {
265 NativeChunk& chr = chunks[nextIndex++];
266 chr.signature = NCS_ReferencesArrayV1;
267 chr.fileOffset = nextFileOffset;
268 chr.fileSize = _references.size() * sizeof(NativeReferenceIvarsV1);
269 chr.elementCount = _references.size();
270 nextFileOffset = chr.fileOffset + chr.fileSize;
271 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000272
273 // create chunk for target table
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000274 if ( hasTargetsTable ) {
275 NativeChunk& cht = chunks[nextIndex++];
276 cht.signature = NCS_TargetsTable;
277 cht.fileOffset = nextFileOffset;
278 cht.fileSize = _targetsTableIndex.size() * sizeof(uint32_t);
279 cht.elementCount = _targetsTableIndex.size();
280 nextFileOffset = cht.fileOffset + cht.fileSize;
281 }
282
Michael J. Spencer765792d2012-04-03 18:40:27 +0000283 // create chunk for addend table
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000284 if ( hasAddendTable ) {
285 NativeChunk& chad = chunks[nextIndex++];
286 chad.signature = NCS_AddendsTable;
287 chad.fileOffset = nextFileOffset;
288 chad.fileSize = _addendsTableIndex.size() * sizeof(Reference::Addend);
289 chad.elementCount = _addendsTableIndex.size();
290 nextFileOffset = chad.fileOffset + chad.fileSize;
291 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000292
293 // create chunk for content
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000294 if ( hasContent ) {
295 NativeChunk& chc = chunks[nextIndex++];
296 chc.signature = NCS_Content;
297 chc.fileOffset = nextFileOffset;
298 chc.fileSize = _contentPool.size();
299 chc.elementCount = _contentPool.size();
300 nextFileOffset = chc.fileOffset + chc.fileSize;
301 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000302
Nick Kledzik23384e82012-02-07 02:59:54 +0000303 _headerBuffer->fileSize = nextFileOffset;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000304 }
305
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000306 // scan header to find particular chunk
307 NativeChunk& findChunk(uint32_t signature) {
308 const uint32_t chunkCount = _headerBuffer->chunkCount;
309 NativeChunk* chunks =
310 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
311 + sizeof(NativeFileHeader));
312 for (uint32_t i=0; i < chunkCount; ++i) {
313 if ( chunks[i].signature == signature )
314 return chunks[i];
315 }
316 assert(0 && "findChunk() signature not found");
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000317 static NativeChunk x; return x; // suppress warning
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000318 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000319
320 // append atom name to string pool and return offset
Nick Kledzik23384e82012-02-07 02:59:54 +0000321 uint32_t getNameOffset(const Atom& atom) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000322 return this->getNameOffset(atom.name());
323 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000324
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000325 // check if name is already in pool or append and return offset
Michael J. Spencere6203a52012-04-03 18:39:40 +0000326 uint32_t getSharedLibraryNameOffset(StringRef name) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000327 assert( ! name.empty() );
328 // look to see if this library name was used by another atom
Michael J. Spencer765792d2012-04-03 18:40:27 +0000329 for(NameToOffsetVector::iterator it = _sharedLibraryNames.begin();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000330 it != _sharedLibraryNames.end(); ++it) {
331 if ( name.equals(it->first) )
332 return it->second;
333 }
334 // first use of this library name
335 uint32_t result = this->getNameOffset(name);
Michael J. Spencere753cbc2012-03-09 05:27:43 +0000336 _sharedLibraryNames.push_back(std::make_pair(name, result));
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000337 return result;
338 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000339
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000340 // append atom name to string pool and return offset
Michael J. Spencere6203a52012-04-03 18:39:40 +0000341 uint32_t getNameOffset(StringRef name) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000342 if ( name.empty() )
343 return 0;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000344 uint32_t result = _stringPool.size();
Michael J. Spencerb5ef4df2012-03-09 05:27:20 +0000345 _stringPool.insert(_stringPool.end(), name.begin(), name.end());
346 _stringPool.push_back(0);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000347 return result;
348 }
349
350 // append atom cotent to content pool and return offset
351 uint32_t getContentOffset(const class DefinedAtom& atom) {
Michael J. Spencer765792d2012-04-03 18:40:27 +0000352 if ( atom.contentType() == DefinedAtom::typeZeroFill )
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000353 return 0;
354 uint32_t result = _contentPool.size();
Michael J. Spencere6203a52012-04-03 18:39:40 +0000355 ArrayRef<uint8_t> cont = atom.rawContent();
Michael J. Spencer846fe662012-01-31 21:46:05 +0000356 _contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000357 return result;
358 }
359
360 // reuse existing attributes entry or create a new one and return offet
361 uint32_t getAttributeOffset(const class DefinedAtom& atom) {
362 NativeAtomAttributesV1 attrs;
363 computeAttributesV1(atom, attrs);
364 for(unsigned int i=0; i < _attributes.size(); ++i) {
365 if ( !memcmp(&_attributes[i], &attrs, sizeof(NativeAtomAttributesV1)) ) {
366 // found that this set of attributes already used, so re-use
367 return i * sizeof(NativeAtomAttributesV1);
368 }
369 }
370 // append new attribute set to end
371 uint32_t result = _attributes.size() * sizeof(NativeAtomAttributesV1);
372 _attributes.push_back(attrs);
373 return result;
374 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000375
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000376 uint32_t sectionNameOffset(const class DefinedAtom& atom) {
377 // if section based on content, then no custom section name available
378 if ( atom.sectionChoice() == DefinedAtom::sectionBasedOnContent )
379 return 0;
Michael J. Spencere6203a52012-04-03 18:39:40 +0000380 StringRef name = atom.customSectionName();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000381 assert( ! name.empty() );
382 // look to see if this section name was used by another atom
Michael J. Spencer765792d2012-04-03 18:40:27 +0000383 for(NameToOffsetVector::iterator it=_sectionNames.begin();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000384 it != _sectionNames.end(); ++it) {
385 if ( name.equals(it->first) )
386 return it->second;
387 }
388 // first use of this section name
389 uint32_t result = this->getNameOffset(name);
Michael J. Spencere753cbc2012-03-09 05:27:43 +0000390 _sectionNames.push_back(std::make_pair(name, result));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000391 return result;
392 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000393
394 void computeAttributesV1(const class DefinedAtom& atom,
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000395 NativeAtomAttributesV1& attrs) {
396 attrs.sectionNameOffset = sectionNameOffset(atom);
397 attrs.align2 = atom.alignment().powerOf2;
398 attrs.alignModulus = atom.alignment().modulus;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000399 attrs.scope = atom.scope();
400 attrs.interposable = atom.interposable();
401 attrs.merge = atom.merge();
402 attrs.contentType = atom.contentType();
403 attrs.sectionChoice = atom.sectionChoice();
404 attrs.deadStrip = atom.deadStrip();
405 attrs.permissions = atom.permissions();
406 //attrs.thumb = atom.isThumb();
407 attrs.alias = atom.isAlias();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000408 }
409
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000410 // add references for this atom in a contiguous block in NCS_ReferencesArrayV1
411 uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& count) {
412 count = 0;
413 size_t startRefSize = _references.size();
414 uint32_t result = startRefSize;
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000415 for (auto it=atom.referencesBegin(), end=atom.referencesEnd();
416 it != end; ++it) {
417 const Reference* ref = *it;
418 NativeReferenceIvarsV1 nref;
419 nref.offsetInAtom = ref->offsetInAtom();
420 nref.kind = ref->kind();
421 nref.targetIndex = this->getTargetIndex(ref->target());
422 nref.addendIndex = this->getAddendIndex(ref->addend());
423 _references.push_back(nref);
424 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000425 count = _references.size() - startRefSize;
426 if ( count == 0 )
427 return 0;
428 else
429 return result;
430 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000431
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000432 uint32_t getTargetIndex(const Atom* target) {
Nick Kledzikb334be12012-04-07 01:31:00 +0000433 if ( target == nullptr )
434 return NativeReferenceIvarsV1::noTarget;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000435 TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
436 if ( pos != _targetsTableIndex.end() ) {
437 return pos->second;
438 }
Nick Kledzikb334be12012-04-07 01:31:00 +0000439 uint32_t result = _targetsTableIndex.size();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000440 _targetsTableIndex[target] = result;
441 return result;
442 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000443
444 void writeTargetTable(raw_ostream &out) {
445 // Build table of target indexes
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000446 uint32_t maxTargetIndex = _targetsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000447 assert(maxTargetIndex > 0);
448 std::vector<uint32_t> targetIndexes(maxTargetIndex);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000449 for (TargetToIndex::iterator it = _targetsTableIndex.begin();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000450 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());
Michael J. Spencer765792d2012-04-03 18:40:27 +0000468 atomIndex = pos->second
469 + _definedAtomIvars.size()
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000470 + _undefinedAtomIndex.size();
471 }
472 else {
473 pos = _absoluteAtomIndex.find(atom);
474 assert(pos != _absoluteAtomIndex.end());
Michael J. Spencer765792d2012-04-03 18:40:27 +0000475 atomIndex = pos->second
476 + _definedAtomIvars.size()
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000477 + _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 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000487
488 uint32_t getAddendIndex(Reference::Addend addend) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000489 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 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000499
Michael J. Spencere6203a52012-04-03 18:39:40 +0000500 void writeAddendTable(raw_ostream &out) {
Michael J. Spencer765792d2012-04-03 18:40:27 +0000501 // Build table of addends
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000502 uint32_t maxAddendIndex = _addendsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000503 std::vector<Reference::Addend> addends(maxAddendIndex);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000504 for (AddendToIndex::iterator it = _addendsTableIndex.begin();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000505 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
Michael J. Spencere6203a52012-04-03 18:39:40 +0000515 typedef std::vector<std::pair<StringRef, uint32_t> > NameToOffsetVector;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000516
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.
Michael J. Spencere6203a52012-04-03 18:39:40 +0000547int writeNativeObjectFile(const File &file, raw_ostream &out) {
548 NativeWriter writer(file);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000549 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.
Michael J. Spencere6203a52012-04-03 18:39:40 +0000555int writeNativeObjectFile(const File &file, StringRef path) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000556 std::string errorInfo;
Michael J. Spencere6203a52012-04-03 18:39:40 +0000557 llvm::raw_fd_ostream out( path.data()
558 , errorInfo
559 , llvm::raw_fd_ostream::F_Binary);
560 if (!errorInfo.empty())
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000561 return -1;
562 return writeNativeObjectFile(file, out);
563}
564
565} // namespace lld