blob: 05fd697ccc02aa49e5f402fdff28932208fd9dfb [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) {
Rui Ueyama3f823e32013-11-15 22:37:34 +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
Rui Ueyama3f823e32013-11-15 22:37:34 +000074 writeChunk(out, _definedAtomIvars, NCS_DefinedAtomsV1);
75 writeChunk(out, _attributes, NCS_AttributesArrayV1);
76 writeChunk(out, _undefinedAtomIvars, NCS_UndefinedAtomsV1);
77 writeChunk(out, _sharedLibraryAtomIvars, NCS_SharedLibraryAtomsV1);
78 writeChunk(out, _absoluteAtomIvars, NCS_AbsoluteAtomsV1);
79 writeChunk(out, _absAttributes, NCS_AbsoluteAttributesV1);
80 writeChunk(out, _stringPool, NCS_Strings);
81 writeChunk(out, _references, NCS_ReferencesArrayV1);
Michael J. Spencer765792d2012-04-03 18:40:27 +000082
Rui Ueyama3f823e32013-11-15 22:37:34 +000083 if (!_targetsTableIndex.empty()) {
84 assert(out.tell() == findChunk(NCS_TargetsTable).fileOffset);
Nick Kledzik49d6cc82012-02-15 00:38:09 +000085 writeTargetTable(out);
86 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000087
Rui Ueyama3f823e32013-11-15 22:37:34 +000088 if (!_addendsTableIndex.empty()) {
89 assert(out.tell() == findChunk(NCS_AddendsTable).fileOffset);
Nick Kledzik49d6cc82012-02-15 00:38:09 +000090 writeAddendTable(out);
91 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000092
Rui Ueyama3f823e32013-11-15 22:37:34 +000093 writeChunk(out, _contentPool, NCS_Content);
94 }
95
96 template<class T>
97 void writeChunk(raw_ostream &out, std::vector<T> &vector, uint32_t signature) {
98 if (vector.empty())
99 return;
100 assert(out.tell() == findChunk(signature).fileOffset);
101 out.write((char*)&vector[0], vector.size() * sizeof(T));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000102 }
103
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000104 void addIVarsForDefinedAtom(const DefinedAtom& atom) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000105 _definedAtomIndex[&atom] = _definedAtomIvars.size();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000106 NativeDefinedAtomIvarsV1 ivar;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000107 unsigned refsCount;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000108 ivar.nameOffset = getNameOffset(atom);
109 ivar.attributesOffset = getAttributeOffset(atom);
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000110 ivar.referencesStartIndex = getReferencesIndex(atom, refsCount);
111 ivar.referencesCount = refsCount;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000112 ivar.contentOffset = getContentOffset(atom);
113 ivar.contentSize = atom.size();
114 _definedAtomIvars.push_back(ivar);
115 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000116
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000117 void addIVarsForUndefinedAtom(const UndefinedAtom& atom) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000118 _undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
Nick Kledzik23384e82012-02-07 02:59:54 +0000119 NativeUndefinedAtomIvarsV1 ivar;
120 ivar.nameOffset = getNameOffset(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000121 ivar.flags = (atom.canBeNull() & 0x03);
Shankar Easwaran0879c1e2013-10-18 03:23:24 +0000122 ivar.fallbackNameOffset = 0;
123 if (atom.fallback())
124 ivar.fallbackNameOffset = getNameOffset(*atom.fallback());
Nick Kledzik23384e82012-02-07 02:59:54 +0000125 _undefinedAtomIvars.push_back(ivar);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000126 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000127
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000128 void addIVarsForSharedLibraryAtom(const SharedLibraryAtom& atom) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000129 _sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
130 NativeSharedLibraryAtomIvarsV1 ivar;
Michael J. Spencer4355bb92013-09-26 22:08:43 +0000131 ivar.size = atom.size();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000132 ivar.nameOffset = getNameOffset(atom);
133 ivar.loadNameOffset = getSharedLibraryNameOffset(atom.loadName());
Michael J. Spencer4355bb92013-09-26 22:08:43 +0000134 ivar.type = (uint32_t)atom.type();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000135 ivar.flags = atom.canBeNullAtRuntime();
136 _sharedLibraryAtomIvars.push_back(ivar);
137 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000138
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000139 void addIVarsForAbsoluteAtom(const AbsoluteAtom& atom) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000140 _absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
141 NativeAbsoluteAtomIvarsV1 ivar;
142 ivar.nameOffset = getNameOffset(atom);
Sid Manning2a590242012-10-18 17:16:19 +0000143 ivar.attributesOffset = getAttributeOffset(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000144 ivar.reserved = 0;
145 ivar.value = atom.value();
146 _absoluteAtomIvars.push_back(ivar);
147 }
148
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000149 // fill out native file header and chunk directory
150 void makeHeader() {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000151 const bool hasDefines = !_definedAtomIvars.empty();
Nick Kledzik23384e82012-02-07 02:59:54 +0000152 const bool hasUndefines = !_undefinedAtomIvars.empty();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000153 const bool hasSharedLibraries = !_sharedLibraryAtomIvars.empty();
154 const bool hasAbsolutes = !_absoluteAtomIvars.empty();
155 const bool hasReferences = !_references.empty();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000156 const bool hasTargetsTable = !_targetsTableIndex.empty();
157 const bool hasAddendTable = !_addendsTableIndex.empty();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000158 const bool hasContent = !_contentPool.empty();
159
160 int chunkCount = 1; // always have string pool chunk
161 if ( hasDefines ) chunkCount += 2;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000162 if ( hasUndefines ) ++chunkCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000163 if ( hasSharedLibraries ) ++chunkCount;
Sid Manning2a590242012-10-18 17:16:19 +0000164 if ( hasAbsolutes ) chunkCount += 2;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000165 if ( hasReferences ) ++chunkCount;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000166 if ( hasTargetsTable ) ++chunkCount;
167 if ( hasAddendTable ) ++chunkCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000168 if ( hasContent ) ++chunkCount;
169
Michael J. Spencer765792d2012-04-03 18:40:27 +0000170 _headerBufferSize = sizeof(NativeFileHeader)
Nick Kledzik23384e82012-02-07 02:59:54 +0000171 + chunkCount*sizeof(NativeChunk);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000172 _headerBuffer = reinterpret_cast<NativeFileHeader*>
173 (operator new(_headerBufferSize, std::nothrow));
Michael J. Spencerb2bd7332012-01-31 21:45:53 +0000174 NativeChunk *chunks =
175 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
176 + sizeof(NativeFileHeader));
Rui Ueyama08588642013-11-15 23:11:00 +0000177 memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC,
178 sizeof(_headerBuffer->magic));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000179 _headerBuffer->endian = NFH_LittleEndian;
180 _headerBuffer->architecture = 0;
181 _headerBuffer->fileSize = 0;
Nick Kledzik23384e82012-02-07 02:59:54 +0000182 _headerBuffer->chunkCount = chunkCount;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000183
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000184 // create chunk for defined atom ivar array
Nick Kledzik23384e82012-02-07 02:59:54 +0000185 int nextIndex = 0;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000186 uint32_t nextFileOffset = _headerBufferSize;
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000187 if (hasDefines) {
188 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _definedAtomIvars,
189 NCS_DefinedAtomsV1);
Nick Kledzik23384e82012-02-07 02:59:54 +0000190
Michael J. Spencer765792d2012-04-03 18:40:27 +0000191 // create chunk for attributes
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000192 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _attributes,
193 NCS_AttributesArrayV1);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000194 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000195
Nick Kledzik23384e82012-02-07 02:59:54 +0000196 // create chunk for undefined atom array
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000197 if (hasUndefines)
198 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _undefinedAtomIvars,
199 NCS_UndefinedAtomsV1);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000200
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000201 // create chunk for shared library atom array
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000202 if (hasSharedLibraries)
203 fillChunkHeader(chunks[nextIndex++], nextFileOffset,
204 _sharedLibraryAtomIvars, NCS_SharedLibraryAtomsV1);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000205
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000206 // create chunk for shared library atom array
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000207 if (hasAbsolutes) {
208 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _absoluteAtomIvars,
209 NCS_AbsoluteAtomsV1);
Sid Manning2a590242012-10-18 17:16:19 +0000210
211 // create chunk for attributes
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000212 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _absAttributes,
213 NCS_AbsoluteAttributesV1);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000214 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000215
Nick Kledzik23384e82012-02-07 02:59:54 +0000216 // create chunk for symbol strings
Michael J. Spencer765792d2012-04-03 18:40:27 +0000217 // pad end of string pool to 4-bytes
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000218 while ((_stringPool.size() % 4) != 0)
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000219 _stringPool.push_back('\0');
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000220 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _stringPool,
221 NCS_Strings);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000222
223 // create chunk for references
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000224 if (hasReferences)
225 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _references,
226 NCS_ReferencesArrayV1);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000227
228 // create chunk for target table
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000229 if (hasTargetsTable) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000230 NativeChunk& cht = chunks[nextIndex++];
231 cht.signature = NCS_TargetsTable;
232 cht.fileOffset = nextFileOffset;
233 cht.fileSize = _targetsTableIndex.size() * sizeof(uint32_t);
234 cht.elementCount = _targetsTableIndex.size();
235 nextFileOffset = cht.fileOffset + cht.fileSize;
236 }
237
Michael J. Spencer765792d2012-04-03 18:40:27 +0000238 // create chunk for addend table
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000239 if (hasAddendTable) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000240 NativeChunk& chad = chunks[nextIndex++];
241 chad.signature = NCS_AddendsTable;
242 chad.fileOffset = nextFileOffset;
243 chad.fileSize = _addendsTableIndex.size() * sizeof(Reference::Addend);
244 chad.elementCount = _addendsTableIndex.size();
245 nextFileOffset = chad.fileOffset + chad.fileSize;
246 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000247
248 // create chunk for content
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000249 if (hasContent)
250 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _contentPool,
251 NCS_Content);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000252
Nick Kledzik23384e82012-02-07 02:59:54 +0000253 _headerBuffer->fileSize = nextFileOffset;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000254 }
255
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000256 template<class T>
257 void fillChunkHeader(NativeChunk &chunk, uint32_t &nextFileOffset,
258 std::vector<T> data, uint32_t signature) {
259 chunk.signature = signature;
260 chunk.fileOffset = nextFileOffset;
261 chunk.fileSize = data.size() * sizeof(T);
262 chunk.elementCount = data.size();
263 nextFileOffset = chunk.fileOffset + chunk.fileSize;
264 }
265
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000266 // scan header to find particular chunk
267 NativeChunk& findChunk(uint32_t signature) {
268 const uint32_t chunkCount = _headerBuffer->chunkCount;
269 NativeChunk* chunks =
270 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
271 + sizeof(NativeFileHeader));
272 for (uint32_t i=0; i < chunkCount; ++i) {
273 if ( chunks[i].signature == signature )
274 return chunks[i];
275 }
Rui Ueyama249becb2013-11-15 23:36:48 +0000276 llvm_unreachable("findChunk() signature not found");
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000277 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000278
279 // append atom name to string pool and return offset
Nick Kledzik23384e82012-02-07 02:59:54 +0000280 uint32_t getNameOffset(const Atom& atom) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000281 return this->getNameOffset(atom.name());
282 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000283
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000284 // check if name is already in pool or append and return offset
Michael J. Spencere6203a52012-04-03 18:39:40 +0000285 uint32_t getSharedLibraryNameOffset(StringRef name) {
Rui Ueyama12027e52013-11-15 23:53:32 +0000286 assert(!name.empty());
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000287 // look to see if this library name was used by another atom
Rui Ueyama12027e52013-11-15 23:53:32 +0000288 for (auto &it : _sharedLibraryNames)
289 if (name.equals(it.first))
290 return it.second;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000291 // first use of this library name
292 uint32_t result = this->getNameOffset(name);
Michael J. Spencere753cbc2012-03-09 05:27:43 +0000293 _sharedLibraryNames.push_back(std::make_pair(name, result));
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000294 return result;
295 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000296
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000297 // append atom name to string pool and return offset
Michael J. Spencere6203a52012-04-03 18:39:40 +0000298 uint32_t getNameOffset(StringRef name) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000299 if ( name.empty() )
300 return 0;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000301 uint32_t result = _stringPool.size();
Michael J. Spencerb5ef4df2012-03-09 05:27:20 +0000302 _stringPool.insert(_stringPool.end(), name.begin(), name.end());
303 _stringPool.push_back(0);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000304 return result;
305 }
306
307 // append atom cotent to content pool and return offset
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000308 uint32_t getContentOffset(const DefinedAtom& atom) {
Shankar Easwarand17ba4b2013-08-23 20:03:21 +0000309 if (!atom.occupiesDiskSpace())
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000310 return 0;
311 uint32_t result = _contentPool.size();
Michael J. Spencere6203a52012-04-03 18:39:40 +0000312 ArrayRef<uint8_t> cont = atom.rawContent();
Michael J. Spencer846fe662012-01-31 21:46:05 +0000313 _contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000314 return result;
315 }
316
317 // reuse existing attributes entry or create a new one and return offet
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000318 uint32_t getAttributeOffset(const DefinedAtom& atom) {
Rui Ueyama4072d912013-11-16 00:55:08 +0000319 NativeAtomAttributesV1 attrs = computeAttributesV1(atom);
320 return getOrPushAttribute(_attributes, attrs);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000321 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000322
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000323 uint32_t getAttributeOffset(const AbsoluteAtom& atom) {
Rui Ueyama4072d912013-11-16 00:55:08 +0000324 NativeAtomAttributesV1 attrs = computeAbsoluteAttributes(atom);
325 return getOrPushAttribute(_absAttributes, attrs);
326 }
327
328 uint32_t getOrPushAttribute(std::vector<NativeAtomAttributesV1> &dest,
329 const NativeAtomAttributesV1 &attrs) {
330 for (size_t i = 0, e = dest.size(); i < e; ++i) {
331 if (!memcmp(&dest[i], &attrs, sizeof(attrs))) {
Sid Manning2a590242012-10-18 17:16:19 +0000332 // found that this set of attributes already used, so re-use
Rui Ueyama4072d912013-11-16 00:55:08 +0000333 return i * sizeof(attrs);
Sid Manning2a590242012-10-18 17:16:19 +0000334 }
335 }
336 // append new attribute set to end
Rui Ueyama4072d912013-11-16 00:55:08 +0000337 uint32_t result = dest.size() * sizeof(attrs);
338 dest.push_back(attrs);
Sid Manning2a590242012-10-18 17:16:19 +0000339 return result;
340 }
341
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000342 uint32_t sectionNameOffset(const DefinedAtom& atom) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000343 // if section based on content, then no custom section name available
Rui Ueyama12027e52013-11-15 23:53:32 +0000344 if (atom.sectionChoice() == DefinedAtom::sectionBasedOnContent)
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000345 return 0;
Michael J. Spencere6203a52012-04-03 18:39:40 +0000346 StringRef name = atom.customSectionName();
Rui Ueyama12027e52013-11-15 23:53:32 +0000347 assert(!name.empty());
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000348 // look to see if this section name was used by another atom
Rui Ueyama12027e52013-11-15 23:53:32 +0000349 for (auto &it : _sectionNames)
350 if (name.equals(it.first))
351 return it.second;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000352 // first use of this section name
353 uint32_t result = this->getNameOffset(name);
Michael J. Spencere753cbc2012-03-09 05:27:43 +0000354 _sectionNames.push_back(std::make_pair(name, result));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000355 return result;
356 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000357
Rui Ueyama4072d912013-11-16 00:55:08 +0000358 NativeAtomAttributesV1 computeAttributesV1(const DefinedAtom& atom) {
359 NativeAtomAttributesV1 attrs;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000360 attrs.sectionNameOffset = sectionNameOffset(atom);
361 attrs.align2 = atom.alignment().powerOf2;
362 attrs.alignModulus = atom.alignment().modulus;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000363 attrs.scope = atom.scope();
364 attrs.interposable = atom.interposable();
365 attrs.merge = atom.merge();
366 attrs.contentType = atom.contentType();
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000367 attrs.sectionChoiceAndPosition
Nick Kledzik36293f62013-01-23 22:32:56 +0000368 = atom.sectionChoice() << 4 | atom.sectionPosition();
Michael J. Spencer765792d2012-04-03 18:40:27 +0000369 attrs.deadStrip = atom.deadStrip();
Michael J. Spencerb8ab9f52013-11-08 21:04:20 +0000370 attrs.dynamicExport = atom.dynamicExport();
Michael J. Spencer765792d2012-04-03 18:40:27 +0000371 attrs.permissions = atom.permissions();
Michael J. Spencer765792d2012-04-03 18:40:27 +0000372 attrs.alias = atom.isAlias();
Rui Ueyama4072d912013-11-16 00:55:08 +0000373 return attrs;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000374 }
375
Rui Ueyama4072d912013-11-16 00:55:08 +0000376 NativeAtomAttributesV1 computeAbsoluteAttributes(const AbsoluteAtom& atom) {
377 NativeAtomAttributesV1 attrs;
378 attrs.scope = atom.scope();
379 return attrs;
Sid Manning2a590242012-10-18 17:16:19 +0000380 }
381
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000382 // add references for this atom in a contiguous block in NCS_ReferencesArrayV1
383 uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& count) {
384 count = 0;
385 size_t startRefSize = _references.size();
386 uint32_t result = startRefSize;
Nick Kledzik062a98c2012-04-08 23:52:13 +0000387 for (const Reference *ref : atom) {
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000388 NativeReferenceIvarsV1 nref;
389 nref.offsetInAtom = ref->offsetInAtom();
390 nref.kind = ref->kind();
391 nref.targetIndex = this->getTargetIndex(ref->target());
392 nref.addendIndex = this->getAddendIndex(ref->addend());
393 _references.push_back(nref);
394 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000395 count = _references.size() - startRefSize;
396 if ( count == 0 )
397 return 0;
398 else
399 return result;
400 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000401
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000402 uint32_t getTargetIndex(const Atom* target) {
Nick Kledzikb334be12012-04-07 01:31:00 +0000403 if ( target == nullptr )
404 return NativeReferenceIvarsV1::noTarget;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000405 TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
406 if ( pos != _targetsTableIndex.end() ) {
407 return pos->second;
408 }
Nick Kledzikabb69812012-05-31 22:34:00 +0000409 uint32_t result = _targetsTableIndex.size();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000410 _targetsTableIndex[target] = result;
411 return result;
412 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000413
414 void writeTargetTable(raw_ostream &out) {
415 // Build table of target indexes
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000416 uint32_t maxTargetIndex = _targetsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000417 assert(maxTargetIndex > 0);
418 std::vector<uint32_t> targetIndexes(maxTargetIndex);
Rui Ueyama12027e52013-11-15 23:53:32 +0000419 for (auto &it : _targetsTableIndex) {
420 const Atom* atom = it.first;
421 uint32_t targetIndex = it.second;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000422 assert(targetIndex < maxTargetIndex);
423 uint32_t atomIndex = 0;
424 TargetToIndex::iterator pos = _definedAtomIndex.find(atom);
425 if ( pos != _definedAtomIndex.end() ) {
426 atomIndex = pos->second;
427 }
428 else {
429 pos = _undefinedAtomIndex.find(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000430 if ( pos != _undefinedAtomIndex.end() ) {
431 atomIndex = pos->second + _definedAtomIvars.size();
432 }
433 else {
434 pos = _sharedLibraryAtomIndex.find(atom);
435 if ( pos != _sharedLibraryAtomIndex.end() ) {
436 assert(pos != _sharedLibraryAtomIndex.end());
Michael J. Spencer765792d2012-04-03 18:40:27 +0000437 atomIndex = pos->second
438 + _definedAtomIvars.size()
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000439 + _undefinedAtomIndex.size();
440 }
441 else {
442 pos = _absoluteAtomIndex.find(atom);
443 assert(pos != _absoluteAtomIndex.end());
Michael J. Spencer765792d2012-04-03 18:40:27 +0000444 atomIndex = pos->second
445 + _definedAtomIvars.size()
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000446 + _undefinedAtomIndex.size()
447 + _sharedLibraryAtomIndex.size();
448 }
449 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000450 }
451 targetIndexes[targetIndex] = atomIndex;
452 }
453 // write table
454 out.write((char*)&targetIndexes[0], maxTargetIndex*sizeof(uint32_t));
455 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000456
457 uint32_t getAddendIndex(Reference::Addend addend) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000458 if ( addend == 0 )
459 return 0; // addend index zero is used to mean "no addend"
460 AddendToIndex::const_iterator pos = _addendsTableIndex.find(addend);
461 if ( pos != _addendsTableIndex.end() ) {
462 return pos->second;
463 }
464 uint32_t result = _addendsTableIndex.size() + 1; // one-based index
465 _addendsTableIndex[addend] = result;
466 return result;
467 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000468
Michael J. Spencere6203a52012-04-03 18:39:40 +0000469 void writeAddendTable(raw_ostream &out) {
Michael J. Spencer765792d2012-04-03 18:40:27 +0000470 // Build table of addends
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000471 uint32_t maxAddendIndex = _addendsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000472 std::vector<Reference::Addend> addends(maxAddendIndex);
Rui Ueyama12027e52013-11-15 23:53:32 +0000473 for (auto &it : _addendsTableIndex) {
474 Reference::Addend addend = it.first;
475 uint32_t index = it.second;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000476 assert(index <= maxAddendIndex);
477 addends[index-1] = addend;
478 }
479 // write table
480 out.write((char*)&addends[0], maxAddendIndex*sizeof(Reference::Addend));
481 }
482
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000483 typedef std::vector<std::pair<StringRef, uint32_t>> NameToOffsetVector;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000484
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000485 typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex;
486 typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex;
487
Nick Kledzik23384e82012-02-07 02:59:54 +0000488 NativeFileHeader* _headerBuffer;
489 size_t _headerBufferSize;
490 std::vector<char> _stringPool;
491 std::vector<uint8_t> _contentPool;
492 std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
493 std::vector<NativeAtomAttributesV1> _attributes;
Sid Manning2a590242012-10-18 17:16:19 +0000494 std::vector<NativeAtomAttributesV1> _absAttributes;
Nick Kledzik23384e82012-02-07 02:59:54 +0000495 std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000496 std::vector<NativeSharedLibraryAtomIvarsV1> _sharedLibraryAtomIvars;
497 std::vector<NativeAbsoluteAtomIvarsV1> _absoluteAtomIvars;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000498 std::vector<NativeReferenceIvarsV1> _references;
499 TargetToIndex _targetsTableIndex;
500 TargetToIndex _definedAtomIndex;
501 TargetToIndex _undefinedAtomIndex;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000502 TargetToIndex _sharedLibraryAtomIndex;
503 TargetToIndex _absoluteAtomIndex;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000504 AddendToIndex _addendsTableIndex;
Nick Kledzik23384e82012-02-07 02:59:54 +0000505 NameToOffsetVector _sectionNames;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000506 NameToOffsetVector _sharedLibraryNames;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000507};
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000508} // end namespace native
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000509
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000510std::unique_ptr<Writer> createWriterNative(const LinkingContext &context) {
511 return std::unique_ptr<Writer>(new native::Writer(context));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000512}
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000513} // end namespace lld