blob: c968a751128d375273f2b478bcccba067015c13b [file] [log] [blame]
Nick Kledzikabb69812012-05-31 22:34:00 +00001//===- lib/ReaderWriter/Native/WriterNative.cpp ---------------------------===//
Nick Kledzik55fd6be2012-01-16 22:03:44 +00002//
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. Spencer64afcb42013-01-23 01:18:43 +000010#include "lld/ReaderWriter/Writer.h"
Michael J. Spencercfd029f2012-03-28 19:04:02 +000011#include "lld/Core/File.h"
Nick Kledzik55fd6be2012-01-16 22:03:44 +000012
Nick Kledzik55fd6be2012-01-16 22:03:44 +000013#include "llvm/ADT/ArrayRef.h"
Nick Kledzik49d6cc82012-02-15 00:38:09 +000014#include "llvm/ADT/DenseMap.h"
Michael J. Spencercfd029f2012-03-28 19:04:02 +000015#include "llvm/ADT/StringRef.h"
Nick Kledzikabb69812012-05-31 22:34:00 +000016#include "llvm/Support/raw_ostream.h"
17#include "llvm/Support/system_error.h"
18
19#include "NativeFileFormat.h"
Nick Kledzik55fd6be2012-01-16 22:03:44 +000020
Michael J. Spencercfd029f2012-03-28 19:04:02 +000021#include <vector>
Nick Kledzik55fd6be2012-01-16 22:03:44 +000022
23namespace lld {
Nick Kledzikabb69812012-05-31 22:34:00 +000024namespace native {
Nick Kledzik55fd6be2012-01-16 22:03:44 +000025
26///
27/// Class for writing native object files.
28///
Nick Kledzikabb69812012-05-31 22:34:00 +000029class Writer : public lld::Writer {
Nick Kledzik55fd6be2012-01-16 22:03:44 +000030public:
Michael J. Spencer64afcb42013-01-23 01:18:43 +000031 Writer(const TargetInfo &ti) {}
Shankar Easwaran8962feb2013-03-14 16:09:49 +000032
Nick Kledzikabb69812012-05-31 22:34:00 +000033 virtual error_code writeFile(const lld::File &file, StringRef outPath) {
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
Nick Kledzik062a98c2012-04-08 23:52:13 +000037 for ( const DefinedAtom *defAtom : file.defined() ) {
38 this->addIVarsForDefinedAtom(*defAtom);
Nick Kledzik1a6615d2012-03-08 00:18:30 +000039 }
Nick Kledzik062a98c2012-04-08 23:52:13 +000040 for ( const UndefinedAtom *undefAtom : file.undefined() ) {
41 this->addIVarsForUndefinedAtom(*undefAtom);
Nick Kledzik1a6615d2012-03-08 00:18:30 +000042 }
Nick Kledzik062a98c2012-04-08 23:52:13 +000043 for ( const SharedLibraryAtom *shlibAtom : file.sharedLibrary() ) {
44 this->addIVarsForSharedLibraryAtom(*shlibAtom);
Nick Kledzik1a6615d2012-03-08 00:18:30 +000045 }
Nick Kledzik062a98c2012-04-08 23:52:13 +000046 for ( const AbsoluteAtom *absAtom : file.absolute() ) {
47 this->addIVarsForAbsoluteAtom(*absAtom);
Nick Kledzik1a6615d2012-03-08 00:18:30 +000048 }
49
Nick Kledzik55fd6be2012-01-16 22:03:44 +000050 // construct file header based on atom information accumulated
Nick Kledzikabb69812012-05-31 22:34:00 +000051 this->makeHeader();
Shankar Easwaran8962feb2013-03-14 16:09:49 +000052
Nick Kledzikabb69812012-05-31 22:34:00 +000053 std::string errorInfo;
54 llvm::raw_fd_ostream out(outPath.data(), errorInfo,
55 llvm::raw_fd_ostream::F_Binary);
56 if (!errorInfo.empty())
57 return error_code::success(); // FIXME
58
59 this->write(out);
Shankar Easwaran8962feb2013-03-14 16:09:49 +000060
Nick Kledzikabb69812012-05-31 22:34:00 +000061 return error_code::success();
Nick Kledzik55fd6be2012-01-16 22:03:44 +000062 }
63
Nick Kledzikabb69812012-05-31 22:34:00 +000064 virtual ~Writer() {
65 }
66
67private:
68
Nick Kledzik55fd6be2012-01-16 22:03:44 +000069 // write the lld::File in native format to the specified stream
Michael J. Spencere6203a52012-04-03 18:39:40 +000070 void write(raw_ostream &out) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +000071 assert( out.tell() == 0 );
Nick Kledzik55fd6be2012-01-16 22:03:44 +000072 out.write((char*)_headerBuffer, _headerBufferSize);
Michael J. Spencer765792d2012-04-03 18:40:27 +000073
Nick Kledzik49d6cc82012-02-15 00:38:09 +000074 if (!_definedAtomIvars.empty()) {
75 assert( out.tell() == findChunk(NCS_DefinedAtomsV1).fileOffset );
Michael J. Spencer8c36f452012-01-31 21:46:41 +000076 out.write((char*)&_definedAtomIvars[0],
77 _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1));
Nick Kledzik49d6cc82012-02-15 00:38:09 +000078 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000079
Nick Kledzik49d6cc82012-02-15 00:38:09 +000080 if (!_attributes.empty()) {
81 assert( out.tell() == findChunk(NCS_AttributesArrayV1).fileOffset );
Michael J. Spencer8c36f452012-01-31 21:46:41 +000082 out.write((char*)&_attributes[0],
83 _attributes.size()*sizeof(NativeAtomAttributesV1));
Nick Kledzik49d6cc82012-02-15 00:38:09 +000084 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000085
Nick Kledzik49d6cc82012-02-15 00:38:09 +000086 if ( !_undefinedAtomIvars.empty() ) {
87 assert( out.tell() == findChunk(NCS_UndefinedAtomsV1).fileOffset );
Michael J. Spencer765792d2012-04-03 18:40:27 +000088 out.write((char*)&_undefinedAtomIvars[0],
Nick Kledzik23384e82012-02-07 02:59:54 +000089 _undefinedAtomIvars.size()*sizeof(NativeUndefinedAtomIvarsV1));
Nick Kledzik49d6cc82012-02-15 00:38:09 +000090 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000091
Nick Kledzik6bc04c62012-02-22 21:56:59 +000092 if ( !_sharedLibraryAtomIvars.empty() ) {
93 assert( out.tell() == findChunk(NCS_SharedLibraryAtomsV1).fileOffset );
Michael J. Spencer765792d2012-04-03 18:40:27 +000094 out.write((char*)&_sharedLibraryAtomIvars[0],
95 _sharedLibraryAtomIvars.size()
Nick Kledzik6bc04c62012-02-22 21:56:59 +000096 * sizeof(NativeSharedLibraryAtomIvarsV1));
97 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000098
Nick Kledzik6bc04c62012-02-22 21:56:59 +000099 if ( !_absoluteAtomIvars.empty() ) {
100 assert( out.tell() == findChunk(NCS_AbsoluteAtomsV1).fileOffset );
Michael J. Spencer765792d2012-04-03 18:40:27 +0000101 out.write((char*)&_absoluteAtomIvars[0],
102 _absoluteAtomIvars.size()
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000103 * sizeof(NativeAbsoluteAtomIvarsV1));
104 }
Sid Manning2a590242012-10-18 17:16:19 +0000105 if (!_absAttributes.empty()) {
106 assert( out.tell() == findChunk(NCS_AbsoluteAttributesV1).fileOffset );
107 out.write((char*)&_absAttributes[0],
108 _absAttributes.size()*sizeof(NativeAtomAttributesV1));
109 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000110
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000111 if (!_stringPool.empty()) {
112 assert( out.tell() == findChunk(NCS_Strings).fileOffset );
Michael J. Spencer8c36f452012-01-31 21:46:41 +0000113 out.write(&_stringPool[0], _stringPool.size());
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000114 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000115
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000116 if ( !_references.empty() ) {
117 assert( out.tell() == findChunk(NCS_ReferencesArrayV1).fileOffset );
Michael J. Spencer765792d2012-04-03 18:40:27 +0000118 out.write((char*)&_references[0],
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000119 _references.size()*sizeof(NativeReferenceIvarsV1));
120 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000121
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000122 if ( !_targetsTableIndex.empty() ) {
123 assert( out.tell() == findChunk(NCS_TargetsTable).fileOffset );
124 writeTargetTable(out);
125 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000126
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000127 if ( !_addendsTableIndex.empty() ) {
128 assert( out.tell() == findChunk(NCS_AddendsTable).fileOffset );
129 writeAddendTable(out);
130 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000131
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000132 if (!_contentPool.empty()) {
133 assert( out.tell() == findChunk(NCS_Content).fileOffset );
Nick Kledzik23384e82012-02-07 02:59:54 +0000134 out.write((char*)&_contentPool[0], _contentPool.size());
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000135 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000136 }
137
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000138 void addIVarsForDefinedAtom(const DefinedAtom& atom) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000139 _definedAtomIndex[&atom] = _definedAtomIvars.size();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000140 NativeDefinedAtomIvarsV1 ivar;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000141 unsigned refsCount;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000142 ivar.nameOffset = getNameOffset(atom);
143 ivar.attributesOffset = getAttributeOffset(atom);
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000144 ivar.referencesStartIndex = getReferencesIndex(atom, refsCount);
145 ivar.referencesCount = refsCount;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000146 ivar.contentOffset = getContentOffset(atom);
147 ivar.contentSize = atom.size();
148 _definedAtomIvars.push_back(ivar);
149 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000150
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000151 void addIVarsForUndefinedAtom(const UndefinedAtom& atom) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000152 _undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
Nick Kledzik23384e82012-02-07 02:59:54 +0000153 NativeUndefinedAtomIvarsV1 ivar;
154 ivar.nameOffset = getNameOffset(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000155 ivar.flags = (atom.canBeNull() & 0x03);
Nick Kledzik23384e82012-02-07 02:59:54 +0000156 _undefinedAtomIvars.push_back(ivar);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000157 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000158
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000159 void addIVarsForSharedLibraryAtom(const SharedLibraryAtom& atom) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000160 _sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
161 NativeSharedLibraryAtomIvarsV1 ivar;
162 ivar.nameOffset = getNameOffset(atom);
163 ivar.loadNameOffset = getSharedLibraryNameOffset(atom.loadName());
164 ivar.flags = atom.canBeNullAtRuntime();
165 _sharedLibraryAtomIvars.push_back(ivar);
166 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000167
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000168 void addIVarsForAbsoluteAtom(const AbsoluteAtom& atom) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000169 _absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
170 NativeAbsoluteAtomIvarsV1 ivar;
171 ivar.nameOffset = getNameOffset(atom);
Sid Manning2a590242012-10-18 17:16:19 +0000172 ivar.attributesOffset = getAttributeOffset(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000173 ivar.reserved = 0;
174 ivar.value = atom.value();
175 _absoluteAtomIvars.push_back(ivar);
176 }
177
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000178 // fill out native file header and chunk directory
179 void makeHeader() {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000180 const bool hasDefines = !_definedAtomIvars.empty();
Nick Kledzik23384e82012-02-07 02:59:54 +0000181 const bool hasUndefines = !_undefinedAtomIvars.empty();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000182 const bool hasSharedLibraries = !_sharedLibraryAtomIvars.empty();
183 const bool hasAbsolutes = !_absoluteAtomIvars.empty();
184 const bool hasReferences = !_references.empty();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000185 const bool hasTargetsTable = !_targetsTableIndex.empty();
186 const bool hasAddendTable = !_addendsTableIndex.empty();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000187 const bool hasContent = !_contentPool.empty();
188
189 int chunkCount = 1; // always have string pool chunk
190 if ( hasDefines ) chunkCount += 2;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000191 if ( hasUndefines ) ++chunkCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000192 if ( hasSharedLibraries ) ++chunkCount;
Sid Manning2a590242012-10-18 17:16:19 +0000193 if ( hasAbsolutes ) chunkCount += 2;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000194 if ( hasReferences ) ++chunkCount;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000195 if ( hasTargetsTable ) ++chunkCount;
196 if ( hasAddendTable ) ++chunkCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000197 if ( hasContent ) ++chunkCount;
198
Michael J. Spencer765792d2012-04-03 18:40:27 +0000199 _headerBufferSize = sizeof(NativeFileHeader)
Nick Kledzik23384e82012-02-07 02:59:54 +0000200 + chunkCount*sizeof(NativeChunk);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000201 _headerBuffer = reinterpret_cast<NativeFileHeader*>
202 (operator new(_headerBufferSize, std::nothrow));
Michael J. Spencerb2bd7332012-01-31 21:45:53 +0000203 NativeChunk *chunks =
204 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
205 + sizeof(NativeFileHeader));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000206 memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC, 16);
207 _headerBuffer->endian = NFH_LittleEndian;
208 _headerBuffer->architecture = 0;
209 _headerBuffer->fileSize = 0;
Nick Kledzik23384e82012-02-07 02:59:54 +0000210 _headerBuffer->chunkCount = chunkCount;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000211
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000212 // create chunk for defined atom ivar array
Nick Kledzik23384e82012-02-07 02:59:54 +0000213 int nextIndex = 0;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000214 uint32_t nextFileOffset = _headerBufferSize;
215 if ( hasDefines ) {
216 NativeChunk& chd = chunks[nextIndex++];
217 chd.signature = NCS_DefinedAtomsV1;
218 chd.fileOffset = nextFileOffset;
219 chd.fileSize = _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1);
220 chd.elementCount = _definedAtomIvars.size();
221 nextFileOffset = chd.fileOffset + chd.fileSize;
Nick Kledzik23384e82012-02-07 02:59:54 +0000222
Michael J. Spencer765792d2012-04-03 18:40:27 +0000223 // create chunk for attributes
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000224 NativeChunk& cha = chunks[nextIndex++];
225 cha.signature = NCS_AttributesArrayV1;
226 cha.fileOffset = nextFileOffset;
227 cha.fileSize = _attributes.size()*sizeof(NativeAtomAttributesV1);
228 cha.elementCount = _attributes.size();
229 nextFileOffset = cha.fileOffset + cha.fileSize;
230 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000231
Nick Kledzik23384e82012-02-07 02:59:54 +0000232 // create chunk for undefined atom array
233 if ( hasUndefines ) {
234 NativeChunk& chu = chunks[nextIndex++];
235 chu.signature = NCS_UndefinedAtomsV1;
236 chu.fileOffset = nextFileOffset;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000237 chu.fileSize = _undefinedAtomIvars.size() *
Nick Kledzik23384e82012-02-07 02:59:54 +0000238 sizeof(NativeUndefinedAtomIvarsV1);
239 chu.elementCount = _undefinedAtomIvars.size();
240 nextFileOffset = chu.fileOffset + chu.fileSize;
241 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000242
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000243 // create chunk for shared library atom array
244 if ( hasSharedLibraries ) {
245 NativeChunk& chsl = chunks[nextIndex++];
246 chsl.signature = NCS_SharedLibraryAtomsV1;
247 chsl.fileOffset = nextFileOffset;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000248 chsl.fileSize = _sharedLibraryAtomIvars.size() *
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000249 sizeof(NativeSharedLibraryAtomIvarsV1);
250 chsl.elementCount = _sharedLibraryAtomIvars.size();
251 nextFileOffset = chsl.fileOffset + chsl.fileSize;
252 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000253
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000254 // create chunk for shared library atom array
255 if ( hasAbsolutes ) {
Sid Manning2a590242012-10-18 17:16:19 +0000256 NativeChunk& chabs = chunks[nextIndex++];
257 chabs.signature = NCS_AbsoluteAtomsV1;
258 chabs.fileOffset = nextFileOffset;
259 chabs.fileSize = _absoluteAtomIvars.size() *
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000260 sizeof(NativeAbsoluteAtomIvarsV1);
Sid Manning2a590242012-10-18 17:16:19 +0000261 chabs.elementCount = _absoluteAtomIvars.size();
262 nextFileOffset = chabs.fileOffset + chabs.fileSize;
263
264 // create chunk for attributes
265 NativeChunk& cha = chunks[nextIndex++];
266 cha.signature = NCS_AbsoluteAttributesV1;
267 cha.fileOffset = nextFileOffset;
268 cha.fileSize = _absAttributes.size()*sizeof(NativeAtomAttributesV1);
269 cha.elementCount = _absAttributes.size();
270 nextFileOffset = cha.fileOffset + cha.fileSize;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000271 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000272
Nick Kledzik23384e82012-02-07 02:59:54 +0000273 // create chunk for symbol strings
Michael J. Spencer765792d2012-04-03 18:40:27 +0000274 // pad end of string pool to 4-bytes
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000275 while ( (_stringPool.size() % 4) != 0 )
276 _stringPool.push_back('\0');
Nick Kledzik23384e82012-02-07 02:59:54 +0000277 NativeChunk& chs = chunks[nextIndex++];
278 chs.signature = NCS_Strings;
279 chs.fileOffset = nextFileOffset;
280 chs.fileSize = _stringPool.size();
281 chs.elementCount = _stringPool.size();
282 nextFileOffset = chs.fileOffset + chs.fileSize;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000283
284 // create chunk for references
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000285 if ( hasReferences ) {
286 NativeChunk& chr = chunks[nextIndex++];
287 chr.signature = NCS_ReferencesArrayV1;
288 chr.fileOffset = nextFileOffset;
289 chr.fileSize = _references.size() * sizeof(NativeReferenceIvarsV1);
290 chr.elementCount = _references.size();
291 nextFileOffset = chr.fileOffset + chr.fileSize;
292 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000293
294 // create chunk for target table
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000295 if ( hasTargetsTable ) {
296 NativeChunk& cht = chunks[nextIndex++];
297 cht.signature = NCS_TargetsTable;
298 cht.fileOffset = nextFileOffset;
299 cht.fileSize = _targetsTableIndex.size() * sizeof(uint32_t);
300 cht.elementCount = _targetsTableIndex.size();
301 nextFileOffset = cht.fileOffset + cht.fileSize;
302 }
303
Michael J. Spencer765792d2012-04-03 18:40:27 +0000304 // create chunk for addend table
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000305 if ( hasAddendTable ) {
306 NativeChunk& chad = chunks[nextIndex++];
307 chad.signature = NCS_AddendsTable;
308 chad.fileOffset = nextFileOffset;
309 chad.fileSize = _addendsTableIndex.size() * sizeof(Reference::Addend);
310 chad.elementCount = _addendsTableIndex.size();
311 nextFileOffset = chad.fileOffset + chad.fileSize;
312 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000313
314 // create chunk for content
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000315 if ( hasContent ) {
316 NativeChunk& chc = chunks[nextIndex++];
317 chc.signature = NCS_Content;
318 chc.fileOffset = nextFileOffset;
319 chc.fileSize = _contentPool.size();
320 chc.elementCount = _contentPool.size();
321 nextFileOffset = chc.fileOffset + chc.fileSize;
322 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000323
Nick Kledzik23384e82012-02-07 02:59:54 +0000324 _headerBuffer->fileSize = nextFileOffset;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000325 }
326
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000327 // scan header to find particular chunk
328 NativeChunk& findChunk(uint32_t signature) {
329 const uint32_t chunkCount = _headerBuffer->chunkCount;
330 NativeChunk* chunks =
331 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
332 + sizeof(NativeFileHeader));
333 for (uint32_t i=0; i < chunkCount; ++i) {
334 if ( chunks[i].signature == signature )
335 return chunks[i];
336 }
337 assert(0 && "findChunk() signature not found");
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000338 static NativeChunk x; return x; // suppress warning
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000339 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000340
341 // append atom name to string pool and return offset
Nick Kledzik23384e82012-02-07 02:59:54 +0000342 uint32_t getNameOffset(const Atom& atom) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000343 return this->getNameOffset(atom.name());
344 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000345
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000346 // check if name is already in pool or append and return offset
Michael J. Spencere6203a52012-04-03 18:39:40 +0000347 uint32_t getSharedLibraryNameOffset(StringRef name) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000348 assert( ! name.empty() );
349 // look to see if this library name was used by another atom
Michael J. Spencer765792d2012-04-03 18:40:27 +0000350 for(NameToOffsetVector::iterator it = _sharedLibraryNames.begin();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000351 it != _sharedLibraryNames.end(); ++it) {
352 if ( name.equals(it->first) )
353 return it->second;
354 }
355 // first use of this library name
356 uint32_t result = this->getNameOffset(name);
Michael J. Spencere753cbc2012-03-09 05:27:43 +0000357 _sharedLibraryNames.push_back(std::make_pair(name, result));
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000358 return result;
359 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000360
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000361 // append atom name to string pool and return offset
Michael J. Spencere6203a52012-04-03 18:39:40 +0000362 uint32_t getNameOffset(StringRef name) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000363 if ( name.empty() )
364 return 0;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000365 uint32_t result = _stringPool.size();
Michael J. Spencerb5ef4df2012-03-09 05:27:20 +0000366 _stringPool.insert(_stringPool.end(), name.begin(), name.end());
367 _stringPool.push_back(0);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000368 return result;
369 }
370
371 // append atom cotent to content pool and return offset
372 uint32_t getContentOffset(const class DefinedAtom& atom) {
Shankar Easwarandb74ffb2013-02-24 03:09:10 +0000373 if ((atom.contentType() == DefinedAtom::typeZeroFill ) ||
374 (atom.contentType() == DefinedAtom::typeZeroFillFast))
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000375 return 0;
376 uint32_t result = _contentPool.size();
Michael J. Spencere6203a52012-04-03 18:39:40 +0000377 ArrayRef<uint8_t> cont = atom.rawContent();
Michael J. Spencer846fe662012-01-31 21:46:05 +0000378 _contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000379 return result;
380 }
381
382 // reuse existing attributes entry or create a new one and return offet
383 uint32_t getAttributeOffset(const class DefinedAtom& atom) {
384 NativeAtomAttributesV1 attrs;
385 computeAttributesV1(atom, attrs);
386 for(unsigned int i=0; i < _attributes.size(); ++i) {
387 if ( !memcmp(&_attributes[i], &attrs, sizeof(NativeAtomAttributesV1)) ) {
388 // found that this set of attributes already used, so re-use
389 return i * sizeof(NativeAtomAttributesV1);
390 }
391 }
392 // append new attribute set to end
393 uint32_t result = _attributes.size() * sizeof(NativeAtomAttributesV1);
394 _attributes.push_back(attrs);
395 return result;
396 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000397
Sid Manning2a590242012-10-18 17:16:19 +0000398 uint32_t getAttributeOffset(const class AbsoluteAtom& atom) {
399 NativeAtomAttributesV1 attrs;
400 computeAbsoluteAttributes(atom, attrs);
401 for(unsigned int i=0; i < _absAttributes.size(); ++i) {
402 if ( !memcmp(&_absAttributes[i], &attrs, sizeof(NativeAtomAttributesV1)) ) {
403 // found that this set of attributes already used, so re-use
404 return i * sizeof(NativeAtomAttributesV1);
405 }
406 }
407 // append new attribute set to end
408 uint32_t result = _absAttributes.size() * sizeof(NativeAtomAttributesV1);
409 _absAttributes.push_back(attrs);
410 return result;
411 }
412
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000413 uint32_t sectionNameOffset(const class DefinedAtom& atom) {
414 // if section based on content, then no custom section name available
415 if ( atom.sectionChoice() == DefinedAtom::sectionBasedOnContent )
416 return 0;
Michael J. Spencere6203a52012-04-03 18:39:40 +0000417 StringRef name = atom.customSectionName();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000418 assert( ! name.empty() );
419 // look to see if this section name was used by another atom
Michael J. Spencer765792d2012-04-03 18:40:27 +0000420 for(NameToOffsetVector::iterator it=_sectionNames.begin();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000421 it != _sectionNames.end(); ++it) {
422 if ( name.equals(it->first) )
423 return it->second;
424 }
425 // first use of this section name
426 uint32_t result = this->getNameOffset(name);
Michael J. Spencere753cbc2012-03-09 05:27:43 +0000427 _sectionNames.push_back(std::make_pair(name, result));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000428 return result;
429 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000430
431 void computeAttributesV1(const class DefinedAtom& atom,
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000432 NativeAtomAttributesV1& attrs) {
433 attrs.sectionNameOffset = sectionNameOffset(atom);
434 attrs.align2 = atom.alignment().powerOf2;
435 attrs.alignModulus = atom.alignment().modulus;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000436 attrs.scope = atom.scope();
437 attrs.interposable = atom.interposable();
438 attrs.merge = atom.merge();
439 attrs.contentType = atom.contentType();
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000440 attrs.sectionChoiceAndPosition
Nick Kledzik36293f62013-01-23 22:32:56 +0000441 = atom.sectionChoice() << 4 | atom.sectionPosition();
Michael J. Spencer765792d2012-04-03 18:40:27 +0000442 attrs.deadStrip = atom.deadStrip();
443 attrs.permissions = atom.permissions();
444 //attrs.thumb = atom.isThumb();
445 attrs.alias = atom.isAlias();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000446 }
447
Sid Manning2a590242012-10-18 17:16:19 +0000448 void computeAbsoluteAttributes(const class AbsoluteAtom& atom,
449 NativeAtomAttributesV1& attrs) {
450 attrs.scope = atom.scope();
451 }
452
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000453 // add references for this atom in a contiguous block in NCS_ReferencesArrayV1
454 uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& count) {
455 count = 0;
456 size_t startRefSize = _references.size();
457 uint32_t result = startRefSize;
Nick Kledzik062a98c2012-04-08 23:52:13 +0000458 for (const Reference *ref : atom) {
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000459 NativeReferenceIvarsV1 nref;
460 nref.offsetInAtom = ref->offsetInAtom();
461 nref.kind = ref->kind();
462 nref.targetIndex = this->getTargetIndex(ref->target());
463 nref.addendIndex = this->getAddendIndex(ref->addend());
464 _references.push_back(nref);
465 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000466 count = _references.size() - startRefSize;
467 if ( count == 0 )
468 return 0;
469 else
470 return result;
471 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000472
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000473 uint32_t getTargetIndex(const Atom* target) {
Nick Kledzikb334be12012-04-07 01:31:00 +0000474 if ( target == nullptr )
475 return NativeReferenceIvarsV1::noTarget;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000476 TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
477 if ( pos != _targetsTableIndex.end() ) {
478 return pos->second;
479 }
Nick Kledzikabb69812012-05-31 22:34:00 +0000480 uint32_t result = _targetsTableIndex.size();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000481 _targetsTableIndex[target] = result;
482 return result;
483 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000484
485 void writeTargetTable(raw_ostream &out) {
486 // Build table of target indexes
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000487 uint32_t maxTargetIndex = _targetsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000488 assert(maxTargetIndex > 0);
489 std::vector<uint32_t> targetIndexes(maxTargetIndex);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000490 for (TargetToIndex::iterator it = _targetsTableIndex.begin();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000491 it != _targetsTableIndex.end(); ++it) {
492 const Atom* atom = it->first;
493 uint32_t targetIndex = it->second;
494 assert(targetIndex < maxTargetIndex);
495 uint32_t atomIndex = 0;
496 TargetToIndex::iterator pos = _definedAtomIndex.find(atom);
497 if ( pos != _definedAtomIndex.end() ) {
498 atomIndex = pos->second;
499 }
500 else {
501 pos = _undefinedAtomIndex.find(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000502 if ( pos != _undefinedAtomIndex.end() ) {
503 atomIndex = pos->second + _definedAtomIvars.size();
504 }
505 else {
506 pos = _sharedLibraryAtomIndex.find(atom);
507 if ( pos != _sharedLibraryAtomIndex.end() ) {
508 assert(pos != _sharedLibraryAtomIndex.end());
Michael J. Spencer765792d2012-04-03 18:40:27 +0000509 atomIndex = pos->second
510 + _definedAtomIvars.size()
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000511 + _undefinedAtomIndex.size();
512 }
513 else {
514 pos = _absoluteAtomIndex.find(atom);
515 assert(pos != _absoluteAtomIndex.end());
Michael J. Spencer765792d2012-04-03 18:40:27 +0000516 atomIndex = pos->second
517 + _definedAtomIvars.size()
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000518 + _undefinedAtomIndex.size()
519 + _sharedLibraryAtomIndex.size();
520 }
521 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000522 }
523 targetIndexes[targetIndex] = atomIndex;
524 }
525 // write table
526 out.write((char*)&targetIndexes[0], maxTargetIndex*sizeof(uint32_t));
527 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000528
529 uint32_t getAddendIndex(Reference::Addend addend) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000530 if ( addend == 0 )
531 return 0; // addend index zero is used to mean "no addend"
532 AddendToIndex::const_iterator pos = _addendsTableIndex.find(addend);
533 if ( pos != _addendsTableIndex.end() ) {
534 return pos->second;
535 }
536 uint32_t result = _addendsTableIndex.size() + 1; // one-based index
537 _addendsTableIndex[addend] = result;
538 return result;
539 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000540
Michael J. Spencere6203a52012-04-03 18:39:40 +0000541 void writeAddendTable(raw_ostream &out) {
Michael J. Spencer765792d2012-04-03 18:40:27 +0000542 // Build table of addends
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000543 uint32_t maxAddendIndex = _addendsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000544 std::vector<Reference::Addend> addends(maxAddendIndex);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000545 for (AddendToIndex::iterator it = _addendsTableIndex.begin();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000546 it != _addendsTableIndex.end(); ++it) {
547 Reference::Addend addend = it->first;
548 uint32_t index = it->second;
549 assert(index <= maxAddendIndex);
550 addends[index-1] = addend;
551 }
552 // write table
553 out.write((char*)&addends[0], maxAddendIndex*sizeof(Reference::Addend));
554 }
555
Michael J. Spencere6203a52012-04-03 18:39:40 +0000556 typedef std::vector<std::pair<StringRef, uint32_t> > NameToOffsetVector;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000557
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000558 typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex;
559 typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex;
560
Nick Kledzik23384e82012-02-07 02:59:54 +0000561 NativeFileHeader* _headerBuffer;
562 size_t _headerBufferSize;
563 std::vector<char> _stringPool;
564 std::vector<uint8_t> _contentPool;
565 std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
566 std::vector<NativeAtomAttributesV1> _attributes;
Sid Manning2a590242012-10-18 17:16:19 +0000567 std::vector<NativeAtomAttributesV1> _absAttributes;
Nick Kledzik23384e82012-02-07 02:59:54 +0000568 std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000569 std::vector<NativeSharedLibraryAtomIvarsV1> _sharedLibraryAtomIvars;
570 std::vector<NativeAbsoluteAtomIvarsV1> _absoluteAtomIvars;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000571 std::vector<NativeReferenceIvarsV1> _references;
572 TargetToIndex _targetsTableIndex;
573 TargetToIndex _definedAtomIndex;
574 TargetToIndex _undefinedAtomIndex;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000575 TargetToIndex _sharedLibraryAtomIndex;
576 TargetToIndex _absoluteAtomIndex;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000577 AddendToIndex _addendsTableIndex;
Nick Kledzik23384e82012-02-07 02:59:54 +0000578 NameToOffsetVector _sectionNames;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000579 NameToOffsetVector _sharedLibraryNames;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000580};
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000581} // end namespace native
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000582
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000583std::unique_ptr<Writer> createWriterNative(const TargetInfo &ti) {
584 return std::unique_ptr<Writer>(new native::Writer(ti));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000585}
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000586} // end namespace lld