blob: 0e6f28365c50b8fb0d8373b37340b3cc2c8703cd [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:
Rui Ueyama0ca149f2013-08-06 22:31:59 +000031 Writer(const LinkingContext &context) {}
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,
Rafael Espindola63f699d2013-07-16 19:44:30 +000055 llvm::sys::fs::F_Binary);
Nick Kledzikabb69812012-05-31 22:34:00 +000056 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
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000372 uint32_t getContentOffset(const 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
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000383 uint32_t getAttributeOffset(const DefinedAtom& atom) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000384 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
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000398 uint32_t getAttributeOffset(const AbsoluteAtom& atom) {
Sid Manning2a590242012-10-18 17:16:19 +0000399 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
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000413 uint32_t sectionNameOffset(const DefinedAtom& atom) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000414 // 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
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000431 void computeAttributesV1(const DefinedAtom& atom,
432 NativeAtomAttributesV1& attrs) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000433 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();
Michael J. Spencer765792d2012-04-03 18:40:27 +0000444 attrs.alias = atom.isAlias();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000445 }
446
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000447 void computeAbsoluteAttributes(const AbsoluteAtom& atom,
448 NativeAtomAttributesV1& attrs) {
Sid Manning2a590242012-10-18 17:16:19 +0000449 attrs.scope = atom.scope();
450 }
451
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000452 // add references for this atom in a contiguous block in NCS_ReferencesArrayV1
453 uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& count) {
454 count = 0;
455 size_t startRefSize = _references.size();
456 uint32_t result = startRefSize;
Nick Kledzik062a98c2012-04-08 23:52:13 +0000457 for (const Reference *ref : atom) {
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000458 NativeReferenceIvarsV1 nref;
459 nref.offsetInAtom = ref->offsetInAtom();
460 nref.kind = ref->kind();
461 nref.targetIndex = this->getTargetIndex(ref->target());
462 nref.addendIndex = this->getAddendIndex(ref->addend());
463 _references.push_back(nref);
464 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000465 count = _references.size() - startRefSize;
466 if ( count == 0 )
467 return 0;
468 else
469 return result;
470 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000471
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000472 uint32_t getTargetIndex(const Atom* target) {
Nick Kledzikb334be12012-04-07 01:31:00 +0000473 if ( target == nullptr )
474 return NativeReferenceIvarsV1::noTarget;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000475 TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
476 if ( pos != _targetsTableIndex.end() ) {
477 return pos->second;
478 }
Nick Kledzikabb69812012-05-31 22:34:00 +0000479 uint32_t result = _targetsTableIndex.size();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000480 _targetsTableIndex[target] = result;
481 return result;
482 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000483
484 void writeTargetTable(raw_ostream &out) {
485 // Build table of target indexes
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000486 uint32_t maxTargetIndex = _targetsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000487 assert(maxTargetIndex > 0);
488 std::vector<uint32_t> targetIndexes(maxTargetIndex);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000489 for (TargetToIndex::iterator it = _targetsTableIndex.begin();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000490 it != _targetsTableIndex.end(); ++it) {
491 const Atom* atom = it->first;
492 uint32_t targetIndex = it->second;
493 assert(targetIndex < maxTargetIndex);
494 uint32_t atomIndex = 0;
495 TargetToIndex::iterator pos = _definedAtomIndex.find(atom);
496 if ( pos != _definedAtomIndex.end() ) {
497 atomIndex = pos->second;
498 }
499 else {
500 pos = _undefinedAtomIndex.find(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000501 if ( pos != _undefinedAtomIndex.end() ) {
502 atomIndex = pos->second + _definedAtomIvars.size();
503 }
504 else {
505 pos = _sharedLibraryAtomIndex.find(atom);
506 if ( pos != _sharedLibraryAtomIndex.end() ) {
507 assert(pos != _sharedLibraryAtomIndex.end());
Michael J. Spencer765792d2012-04-03 18:40:27 +0000508 atomIndex = pos->second
509 + _definedAtomIvars.size()
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000510 + _undefinedAtomIndex.size();
511 }
512 else {
513 pos = _absoluteAtomIndex.find(atom);
514 assert(pos != _absoluteAtomIndex.end());
Michael J. Spencer765792d2012-04-03 18:40:27 +0000515 atomIndex = pos->second
516 + _definedAtomIvars.size()
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000517 + _undefinedAtomIndex.size()
518 + _sharedLibraryAtomIndex.size();
519 }
520 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000521 }
522 targetIndexes[targetIndex] = atomIndex;
523 }
524 // write table
525 out.write((char*)&targetIndexes[0], maxTargetIndex*sizeof(uint32_t));
526 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000527
528 uint32_t getAddendIndex(Reference::Addend addend) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000529 if ( addend == 0 )
530 return 0; // addend index zero is used to mean "no addend"
531 AddendToIndex::const_iterator pos = _addendsTableIndex.find(addend);
532 if ( pos != _addendsTableIndex.end() ) {
533 return pos->second;
534 }
535 uint32_t result = _addendsTableIndex.size() + 1; // one-based index
536 _addendsTableIndex[addend] = result;
537 return result;
538 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000539
Michael J. Spencere6203a52012-04-03 18:39:40 +0000540 void writeAddendTable(raw_ostream &out) {
Michael J. Spencer765792d2012-04-03 18:40:27 +0000541 // Build table of addends
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000542 uint32_t maxAddendIndex = _addendsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000543 std::vector<Reference::Addend> addends(maxAddendIndex);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000544 for (AddendToIndex::iterator it = _addendsTableIndex.begin();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000545 it != _addendsTableIndex.end(); ++it) {
546 Reference::Addend addend = it->first;
547 uint32_t index = it->second;
548 assert(index <= maxAddendIndex);
549 addends[index-1] = addend;
550 }
551 // write table
552 out.write((char*)&addends[0], maxAddendIndex*sizeof(Reference::Addend));
553 }
554
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000555 typedef std::vector<std::pair<StringRef, uint32_t>> NameToOffsetVector;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000556
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000557 typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex;
558 typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex;
559
Nick Kledzik23384e82012-02-07 02:59:54 +0000560 NativeFileHeader* _headerBuffer;
561 size_t _headerBufferSize;
562 std::vector<char> _stringPool;
563 std::vector<uint8_t> _contentPool;
564 std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
565 std::vector<NativeAtomAttributesV1> _attributes;
Sid Manning2a590242012-10-18 17:16:19 +0000566 std::vector<NativeAtomAttributesV1> _absAttributes;
Nick Kledzik23384e82012-02-07 02:59:54 +0000567 std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000568 std::vector<NativeSharedLibraryAtomIvarsV1> _sharedLibraryAtomIvars;
569 std::vector<NativeAbsoluteAtomIvarsV1> _absoluteAtomIvars;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000570 std::vector<NativeReferenceIvarsV1> _references;
571 TargetToIndex _targetsTableIndex;
572 TargetToIndex _definedAtomIndex;
573 TargetToIndex _undefinedAtomIndex;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000574 TargetToIndex _sharedLibraryAtomIndex;
575 TargetToIndex _absoluteAtomIndex;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000576 AddendToIndex _addendsTableIndex;
Nick Kledzik23384e82012-02-07 02:59:54 +0000577 NameToOffsetVector _sectionNames;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000578 NameToOffsetVector _sharedLibraryNames;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000579};
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000580} // end namespace native
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000581
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000582std::unique_ptr<Writer> createWriterNative(const LinkingContext &context) {
583 return std::unique_ptr<Writer>(new native::Writer(context));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000584}
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000585} // end namespace lld