blob: 317ad42c4f0421024c2c957ff89891ecd92208ea [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
Rui Ueyamae05b6292013-11-20 20:54:18 +000021#include <cstdint>
22#include <set>
Michael J. Spencercfd029f2012-03-28 19:04:02 +000023#include <vector>
Nick Kledzik55fd6be2012-01-16 22:03:44 +000024
25namespace lld {
Nick Kledzikabb69812012-05-31 22:34:00 +000026namespace native {
Nick Kledzik55fd6be2012-01-16 22:03:44 +000027
28///
29/// Class for writing native object files.
30///
Nick Kledzikabb69812012-05-31 22:34:00 +000031class Writer : public lld::Writer {
Nick Kledzik55fd6be2012-01-16 22:03:44 +000032public:
Rui Ueyama0ca149f2013-08-06 22:31:59 +000033 Writer(const LinkingContext &context) {}
Shankar Easwaran8962feb2013-03-14 16:09:49 +000034
Nick Kledzikabb69812012-05-31 22:34:00 +000035 virtual error_code writeFile(const lld::File &file, StringRef outPath) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +000036 // reserve first byte for unnamed atoms
37 _stringPool.push_back('\0');
Nick Kledzik55fd6be2012-01-16 22:03:44 +000038 // visit all atoms
Nick Kledzik062a98c2012-04-08 23:52:13 +000039 for ( const DefinedAtom *defAtom : file.defined() ) {
40 this->addIVarsForDefinedAtom(*defAtom);
Nick Kledzik1a6615d2012-03-08 00:18:30 +000041 }
Nick Kledzik062a98c2012-04-08 23:52:13 +000042 for ( const UndefinedAtom *undefAtom : file.undefined() ) {
43 this->addIVarsForUndefinedAtom(*undefAtom);
Nick Kledzik1a6615d2012-03-08 00:18:30 +000044 }
Nick Kledzik062a98c2012-04-08 23:52:13 +000045 for ( const SharedLibraryAtom *shlibAtom : file.sharedLibrary() ) {
46 this->addIVarsForSharedLibraryAtom(*shlibAtom);
Nick Kledzik1a6615d2012-03-08 00:18:30 +000047 }
Nick Kledzik062a98c2012-04-08 23:52:13 +000048 for ( const AbsoluteAtom *absAtom : file.absolute() ) {
49 this->addIVarsForAbsoluteAtom(*absAtom);
Nick Kledzik1a6615d2012-03-08 00:18:30 +000050 }
51
Rui Ueyamae05b6292013-11-20 20:54:18 +000052 maybeConvertReferencesToV1();
53
Nick Kledzik55fd6be2012-01-16 22:03:44 +000054 // construct file header based on atom information accumulated
Nick Kledzikabb69812012-05-31 22:34:00 +000055 this->makeHeader();
Shankar Easwaran8962feb2013-03-14 16:09:49 +000056
Nick Kledzikabb69812012-05-31 22:34:00 +000057 std::string errorInfo;
58 llvm::raw_fd_ostream out(outPath.data(), errorInfo,
Rafael Espindolaf27f9fa2014-02-24 18:20:36 +000059 llvm::sys::fs::F_None);
Nick Kledzikabb69812012-05-31 22:34:00 +000060 if (!errorInfo.empty())
61 return error_code::success(); // FIXME
62
63 this->write(out);
Shankar Easwaran8962feb2013-03-14 16:09:49 +000064
Nick Kledzikabb69812012-05-31 22:34:00 +000065 return error_code::success();
Nick Kledzik55fd6be2012-01-16 22:03:44 +000066 }
67
Nick Kledzikabb69812012-05-31 22:34:00 +000068 virtual ~Writer() {
69 }
70
71private:
72
Nick Kledzik55fd6be2012-01-16 22:03:44 +000073 // write the lld::File in native format to the specified stream
Michael J. Spencere6203a52012-04-03 18:39:40 +000074 void write(raw_ostream &out) {
Rui Ueyama3f823e32013-11-15 22:37:34 +000075 assert(out.tell() == 0);
Nick Kledzik55fd6be2012-01-16 22:03:44 +000076 out.write((char*)_headerBuffer, _headerBufferSize);
Michael J. Spencer765792d2012-04-03 18:40:27 +000077
Rui Ueyama3f823e32013-11-15 22:37:34 +000078 writeChunk(out, _definedAtomIvars, NCS_DefinedAtomsV1);
79 writeChunk(out, _attributes, NCS_AttributesArrayV1);
80 writeChunk(out, _undefinedAtomIvars, NCS_UndefinedAtomsV1);
81 writeChunk(out, _sharedLibraryAtomIvars, NCS_SharedLibraryAtomsV1);
82 writeChunk(out, _absoluteAtomIvars, NCS_AbsoluteAtomsV1);
83 writeChunk(out, _absAttributes, NCS_AbsoluteAttributesV1);
84 writeChunk(out, _stringPool, NCS_Strings);
Rui Ueyamae05b6292013-11-20 20:54:18 +000085 writeChunk(out, _referencesV1, NCS_ReferencesArrayV1);
86 writeChunk(out, _referencesV2, NCS_ReferencesArrayV2);
Michael J. Spencer765792d2012-04-03 18:40:27 +000087
Rui Ueyama3f823e32013-11-15 22:37:34 +000088 if (!_targetsTableIndex.empty()) {
89 assert(out.tell() == findChunk(NCS_TargetsTable).fileOffset);
Nick Kledzik49d6cc82012-02-15 00:38:09 +000090 writeTargetTable(out);
91 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000092
Rui Ueyama3f823e32013-11-15 22:37:34 +000093 if (!_addendsTableIndex.empty()) {
94 assert(out.tell() == findChunk(NCS_AddendsTable).fileOffset);
Nick Kledzik49d6cc82012-02-15 00:38:09 +000095 writeAddendTable(out);
96 }
Michael J. Spencer765792d2012-04-03 18:40:27 +000097
Rui Ueyama3f823e32013-11-15 22:37:34 +000098 writeChunk(out, _contentPool, NCS_Content);
99 }
100
101 template<class T>
102 void writeChunk(raw_ostream &out, std::vector<T> &vector, uint32_t signature) {
103 if (vector.empty())
104 return;
105 assert(out.tell() == findChunk(signature).fileOffset);
106 out.write((char*)&vector[0], vector.size() * sizeof(T));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000107 }
108
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000109 void addIVarsForDefinedAtom(const DefinedAtom& atom) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000110 _definedAtomIndex[&atom] = _definedAtomIvars.size();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000111 NativeDefinedAtomIvarsV1 ivar;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000112 unsigned refsCount;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000113 ivar.nameOffset = getNameOffset(atom);
114 ivar.attributesOffset = getAttributeOffset(atom);
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000115 ivar.referencesStartIndex = getReferencesIndex(atom, refsCount);
116 ivar.referencesCount = refsCount;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000117 ivar.contentOffset = getContentOffset(atom);
118 ivar.contentSize = atom.size();
119 _definedAtomIvars.push_back(ivar);
120 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000121
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000122 void addIVarsForUndefinedAtom(const UndefinedAtom& atom) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000123 _undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
Nick Kledzik23384e82012-02-07 02:59:54 +0000124 NativeUndefinedAtomIvarsV1 ivar;
125 ivar.nameOffset = getNameOffset(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000126 ivar.flags = (atom.canBeNull() & 0x03);
Shankar Easwaran0879c1e2013-10-18 03:23:24 +0000127 ivar.fallbackNameOffset = 0;
128 if (atom.fallback())
129 ivar.fallbackNameOffset = getNameOffset(*atom.fallback());
Nick Kledzik23384e82012-02-07 02:59:54 +0000130 _undefinedAtomIvars.push_back(ivar);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000131 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000132
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000133 void addIVarsForSharedLibraryAtom(const SharedLibraryAtom& atom) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000134 _sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
135 NativeSharedLibraryAtomIvarsV1 ivar;
Michael J. Spencer4355bb92013-09-26 22:08:43 +0000136 ivar.size = atom.size();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000137 ivar.nameOffset = getNameOffset(atom);
138 ivar.loadNameOffset = getSharedLibraryNameOffset(atom.loadName());
Michael J. Spencer4355bb92013-09-26 22:08:43 +0000139 ivar.type = (uint32_t)atom.type();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000140 ivar.flags = atom.canBeNullAtRuntime();
141 _sharedLibraryAtomIvars.push_back(ivar);
142 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000143
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000144 void addIVarsForAbsoluteAtom(const AbsoluteAtom& atom) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000145 _absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
146 NativeAbsoluteAtomIvarsV1 ivar;
147 ivar.nameOffset = getNameOffset(atom);
Sid Manning2a590242012-10-18 17:16:19 +0000148 ivar.attributesOffset = getAttributeOffset(atom);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000149 ivar.reserved = 0;
150 ivar.value = atom.value();
151 _absoluteAtomIvars.push_back(ivar);
152 }
153
Rui Ueyamae05b6292013-11-20 20:54:18 +0000154 void convertReferencesToV1() {
155 for (const NativeReferenceIvarsV2 &v2 : _referencesV2) {
156 NativeReferenceIvarsV1 v1;
157 v1.offsetInAtom = v2.offsetInAtom;
Nick Kledzike5552772013-12-19 21:58:00 +0000158 v1.kindNamespace = v2.kindNamespace;
159 v1.kindArch = v2.kindArch;
160 v1.kindValue = v2.kindValue;
Rui Ueyamae05b6292013-11-20 20:54:18 +0000161 v1.targetIndex = (v2.targetIndex == NativeReferenceIvarsV2::noTarget) ?
162 NativeReferenceIvarsV1::noTarget : v2.targetIndex;
163 v1.addendIndex = this->getAddendIndex(v2.addend);
164 _referencesV1.push_back(v1);
165 }
166 _referencesV2.clear();
167 }
168
169 bool canConvertReferenceToV1(const NativeReferenceIvarsV2 &ref) {
170 bool validOffset = (ref.offsetInAtom == NativeReferenceIvarsV2::noTarget) ||
171 ref.offsetInAtom < NativeReferenceIvarsV1::noTarget;
172 return validOffset && ref.targetIndex < UINT16_MAX;
173 }
174
175 // Convert vector of NativeReferenceIvarsV2 to NativeReferenceIvarsV1 if
176 // possible.
177 void maybeConvertReferencesToV1() {
178 std::set<int64_t> addends;
179 for (const NativeReferenceIvarsV2 &ref : _referencesV2) {
180 if (!canConvertReferenceToV1(ref))
181 return;
182 addends.insert(ref.addend);
183 if (addends.size() >= UINT16_MAX)
184 return;
185 }
186 convertReferencesToV1();
187 }
188
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000189 // fill out native file header and chunk directory
190 void makeHeader() {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000191 const bool hasDefines = !_definedAtomIvars.empty();
Nick Kledzik23384e82012-02-07 02:59:54 +0000192 const bool hasUndefines = !_undefinedAtomIvars.empty();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000193 const bool hasSharedLibraries = !_sharedLibraryAtomIvars.empty();
194 const bool hasAbsolutes = !_absoluteAtomIvars.empty();
Rui Ueyamae05b6292013-11-20 20:54:18 +0000195 const bool hasReferencesV1 = !_referencesV1.empty();
196 const bool hasReferencesV2 = !_referencesV2.empty();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000197 const bool hasTargetsTable = !_targetsTableIndex.empty();
198 const bool hasAddendTable = !_addendsTableIndex.empty();
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000199 const bool hasContent = !_contentPool.empty();
200
201 int chunkCount = 1; // always have string pool chunk
202 if ( hasDefines ) chunkCount += 2;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000203 if ( hasUndefines ) ++chunkCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000204 if ( hasSharedLibraries ) ++chunkCount;
Sid Manning2a590242012-10-18 17:16:19 +0000205 if ( hasAbsolutes ) chunkCount += 2;
Rui Ueyamae05b6292013-11-20 20:54:18 +0000206 if ( hasReferencesV1 ) ++chunkCount;
207 if ( hasReferencesV2 ) ++chunkCount;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000208 if ( hasTargetsTable ) ++chunkCount;
209 if ( hasAddendTable ) ++chunkCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000210 if ( hasContent ) ++chunkCount;
211
Michael J. Spencer765792d2012-04-03 18:40:27 +0000212 _headerBufferSize = sizeof(NativeFileHeader)
Nick Kledzik23384e82012-02-07 02:59:54 +0000213 + chunkCount*sizeof(NativeChunk);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000214 _headerBuffer = reinterpret_cast<NativeFileHeader*>
215 (operator new(_headerBufferSize, std::nothrow));
Michael J. Spencerb2bd7332012-01-31 21:45:53 +0000216 NativeChunk *chunks =
217 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
218 + sizeof(NativeFileHeader));
Rui Ueyama08588642013-11-15 23:11:00 +0000219 memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC,
220 sizeof(_headerBuffer->magic));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000221 _headerBuffer->endian = NFH_LittleEndian;
222 _headerBuffer->architecture = 0;
223 _headerBuffer->fileSize = 0;
Nick Kledzik23384e82012-02-07 02:59:54 +0000224 _headerBuffer->chunkCount = chunkCount;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000225
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000226 // create chunk for defined atom ivar array
Nick Kledzik23384e82012-02-07 02:59:54 +0000227 int nextIndex = 0;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000228 uint32_t nextFileOffset = _headerBufferSize;
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000229 if (hasDefines) {
230 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _definedAtomIvars,
231 NCS_DefinedAtomsV1);
Nick Kledzik23384e82012-02-07 02:59:54 +0000232
Michael J. Spencer765792d2012-04-03 18:40:27 +0000233 // create chunk for attributes
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000234 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _attributes,
235 NCS_AttributesArrayV1);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000236 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000237
Nick Kledzik23384e82012-02-07 02:59:54 +0000238 // create chunk for undefined atom array
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000239 if (hasUndefines)
240 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _undefinedAtomIvars,
241 NCS_UndefinedAtomsV1);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000242
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000243 // create chunk for shared library atom array
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000244 if (hasSharedLibraries)
245 fillChunkHeader(chunks[nextIndex++], nextFileOffset,
246 _sharedLibraryAtomIvars, NCS_SharedLibraryAtomsV1);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000247
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000248 // create chunk for shared library atom array
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000249 if (hasAbsolutes) {
250 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _absoluteAtomIvars,
251 NCS_AbsoluteAtomsV1);
Sid Manning2a590242012-10-18 17:16:19 +0000252
253 // create chunk for attributes
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000254 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _absAttributes,
255 NCS_AbsoluteAttributesV1);
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000256 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000257
Nick Kledzik23384e82012-02-07 02:59:54 +0000258 // create chunk for symbol strings
Michael J. Spencer765792d2012-04-03 18:40:27 +0000259 // pad end of string pool to 4-bytes
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000260 while ((_stringPool.size() % 4) != 0)
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000261 _stringPool.push_back('\0');
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000262 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _stringPool,
263 NCS_Strings);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000264
Rui Ueyamae05b6292013-11-20 20:54:18 +0000265 // create chunk for referencesV2
266 if (hasReferencesV1)
267 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _referencesV1,
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000268 NCS_ReferencesArrayV1);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000269
Rui Ueyamae05b6292013-11-20 20:54:18 +0000270 // create chunk for referencesV2
271 if (hasReferencesV2)
272 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _referencesV2,
273 NCS_ReferencesArrayV2);
274
Michael J. Spencer765792d2012-04-03 18:40:27 +0000275 // create chunk for target table
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000276 if (hasTargetsTable) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000277 NativeChunk& cht = chunks[nextIndex++];
278 cht.signature = NCS_TargetsTable;
279 cht.fileOffset = nextFileOffset;
280 cht.fileSize = _targetsTableIndex.size() * sizeof(uint32_t);
281 cht.elementCount = _targetsTableIndex.size();
282 nextFileOffset = cht.fileOffset + cht.fileSize;
283 }
284
Michael J. Spencer765792d2012-04-03 18:40:27 +0000285 // create chunk for addend table
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000286 if (hasAddendTable) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000287 NativeChunk& chad = chunks[nextIndex++];
288 chad.signature = NCS_AddendsTable;
289 chad.fileOffset = nextFileOffset;
290 chad.fileSize = _addendsTableIndex.size() * sizeof(Reference::Addend);
291 chad.elementCount = _addendsTableIndex.size();
292 nextFileOffset = chad.fileOffset + chad.fileSize;
293 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000294
295 // create chunk for content
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000296 if (hasContent)
297 fillChunkHeader(chunks[nextIndex++], nextFileOffset, _contentPool,
298 NCS_Content);
Michael J. Spencer765792d2012-04-03 18:40:27 +0000299
Nick Kledzik23384e82012-02-07 02:59:54 +0000300 _headerBuffer->fileSize = nextFileOffset;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000301 }
302
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000303 template<class T>
304 void fillChunkHeader(NativeChunk &chunk, uint32_t &nextFileOffset,
Rui Ueyama11d1f182013-11-18 04:05:28 +0000305 const std::vector<T> &data, uint32_t signature) {
Rui Ueyama559b0aa2013-11-15 23:28:58 +0000306 chunk.signature = signature;
307 chunk.fileOffset = nextFileOffset;
308 chunk.fileSize = data.size() * sizeof(T);
309 chunk.elementCount = data.size();
310 nextFileOffset = chunk.fileOffset + chunk.fileSize;
311 }
312
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000313 // scan header to find particular chunk
314 NativeChunk& findChunk(uint32_t signature) {
315 const uint32_t chunkCount = _headerBuffer->chunkCount;
316 NativeChunk* chunks =
317 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
318 + sizeof(NativeFileHeader));
319 for (uint32_t i=0; i < chunkCount; ++i) {
320 if ( chunks[i].signature == signature )
321 return chunks[i];
322 }
Rui Ueyama249becb2013-11-15 23:36:48 +0000323 llvm_unreachable("findChunk() signature not found");
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000324 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000325
326 // append atom name to string pool and return offset
Nick Kledzik23384e82012-02-07 02:59:54 +0000327 uint32_t getNameOffset(const Atom& atom) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000328 return this->getNameOffset(atom.name());
329 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000330
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000331 // check if name is already in pool or append and return offset
Michael J. Spencere6203a52012-04-03 18:39:40 +0000332 uint32_t getSharedLibraryNameOffset(StringRef name) {
Rui Ueyama12027e52013-11-15 23:53:32 +0000333 assert(!name.empty());
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000334 // look to see if this library name was used by another atom
Rui Ueyama12027e52013-11-15 23:53:32 +0000335 for (auto &it : _sharedLibraryNames)
336 if (name.equals(it.first))
337 return it.second;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000338 // first use of this library name
339 uint32_t result = this->getNameOffset(name);
Michael J. Spencere753cbc2012-03-09 05:27:43 +0000340 _sharedLibraryNames.push_back(std::make_pair(name, result));
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000341 return result;
342 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000343
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000344 // append atom name to string pool and return offset
Michael J. Spencere6203a52012-04-03 18:39:40 +0000345 uint32_t getNameOffset(StringRef name) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000346 if ( name.empty() )
347 return 0;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000348 uint32_t result = _stringPool.size();
Michael J. Spencerb5ef4df2012-03-09 05:27:20 +0000349 _stringPool.insert(_stringPool.end(), name.begin(), name.end());
350 _stringPool.push_back(0);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000351 return result;
352 }
353
354 // append atom cotent to content pool and return offset
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000355 uint32_t getContentOffset(const DefinedAtom& atom) {
Shankar Easwarand17ba4b2013-08-23 20:03:21 +0000356 if (!atom.occupiesDiskSpace())
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000357 return 0;
358 uint32_t result = _contentPool.size();
Michael J. Spencere6203a52012-04-03 18:39:40 +0000359 ArrayRef<uint8_t> cont = atom.rawContent();
Michael J. Spencer846fe662012-01-31 21:46:05 +0000360 _contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000361 return result;
362 }
363
364 // reuse existing attributes entry or create a new one and return offet
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000365 uint32_t getAttributeOffset(const DefinedAtom& atom) {
Rui Ueyama4072d912013-11-16 00:55:08 +0000366 NativeAtomAttributesV1 attrs = computeAttributesV1(atom);
367 return getOrPushAttribute(_attributes, attrs);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000368 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000369
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000370 uint32_t getAttributeOffset(const AbsoluteAtom& atom) {
Rui Ueyama4072d912013-11-16 00:55:08 +0000371 NativeAtomAttributesV1 attrs = computeAbsoluteAttributes(atom);
372 return getOrPushAttribute(_absAttributes, attrs);
373 }
374
375 uint32_t getOrPushAttribute(std::vector<NativeAtomAttributesV1> &dest,
376 const NativeAtomAttributesV1 &attrs) {
377 for (size_t i = 0, e = dest.size(); i < e; ++i) {
378 if (!memcmp(&dest[i], &attrs, sizeof(attrs))) {
Sid Manning2a590242012-10-18 17:16:19 +0000379 // found that this set of attributes already used, so re-use
Rui Ueyama4072d912013-11-16 00:55:08 +0000380 return i * sizeof(attrs);
Sid Manning2a590242012-10-18 17:16:19 +0000381 }
382 }
383 // append new attribute set to end
Rui Ueyama4072d912013-11-16 00:55:08 +0000384 uint32_t result = dest.size() * sizeof(attrs);
385 dest.push_back(attrs);
Sid Manning2a590242012-10-18 17:16:19 +0000386 return result;
387 }
388
Rui Ueyama7b7b0b92013-06-21 19:59:15 +0000389 uint32_t sectionNameOffset(const DefinedAtom& atom) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000390 // if section based on content, then no custom section name available
Rui Ueyama12027e52013-11-15 23:53:32 +0000391 if (atom.sectionChoice() == DefinedAtom::sectionBasedOnContent)
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000392 return 0;
Michael J. Spencere6203a52012-04-03 18:39:40 +0000393 StringRef name = atom.customSectionName();
Rui Ueyama12027e52013-11-15 23:53:32 +0000394 assert(!name.empty());
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000395 // look to see if this section name was used by another atom
Rui Ueyama12027e52013-11-15 23:53:32 +0000396 for (auto &it : _sectionNames)
397 if (name.equals(it.first))
398 return it.second;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000399 // first use of this section name
400 uint32_t result = this->getNameOffset(name);
Michael J. Spencere753cbc2012-03-09 05:27:43 +0000401 _sectionNames.push_back(std::make_pair(name, result));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000402 return result;
403 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000404
Rui Ueyama4072d912013-11-16 00:55:08 +0000405 NativeAtomAttributesV1 computeAttributesV1(const DefinedAtom& atom) {
406 NativeAtomAttributesV1 attrs;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000407 attrs.sectionNameOffset = sectionNameOffset(atom);
408 attrs.align2 = atom.alignment().powerOf2;
409 attrs.alignModulus = atom.alignment().modulus;
Michael J. Spencer765792d2012-04-03 18:40:27 +0000410 attrs.scope = atom.scope();
411 attrs.interposable = atom.interposable();
412 attrs.merge = atom.merge();
413 attrs.contentType = atom.contentType();
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000414 attrs.sectionChoiceAndPosition
Nick Kledzik36293f62013-01-23 22:32:56 +0000415 = atom.sectionChoice() << 4 | atom.sectionPosition();
Michael J. Spencer765792d2012-04-03 18:40:27 +0000416 attrs.deadStrip = atom.deadStrip();
Michael J. Spencerb8ab9f52013-11-08 21:04:20 +0000417 attrs.dynamicExport = atom.dynamicExport();
Michael J. Spencer765792d2012-04-03 18:40:27 +0000418 attrs.permissions = atom.permissions();
Michael J. Spencer765792d2012-04-03 18:40:27 +0000419 attrs.alias = atom.isAlias();
Rui Ueyama4072d912013-11-16 00:55:08 +0000420 return attrs;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000421 }
422
Rui Ueyama4072d912013-11-16 00:55:08 +0000423 NativeAtomAttributesV1 computeAbsoluteAttributes(const AbsoluteAtom& atom) {
424 NativeAtomAttributesV1 attrs;
425 attrs.scope = atom.scope();
426 return attrs;
Sid Manning2a590242012-10-18 17:16:19 +0000427 }
428
Rui Ueyamae05b6292013-11-20 20:54:18 +0000429 // add references for this atom in a contiguous block in NCS_ReferencesArrayV2
Rui Ueyamae4d20ab2013-11-16 01:01:35 +0000430 uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& refsCount) {
Rui Ueyamae05b6292013-11-20 20:54:18 +0000431 size_t startRefSize = _referencesV2.size();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000432 uint32_t result = startRefSize;
Nick Kledzik062a98c2012-04-08 23:52:13 +0000433 for (const Reference *ref : atom) {
Rui Ueyamae05b6292013-11-20 20:54:18 +0000434 NativeReferenceIvarsV2 nref;
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000435 nref.offsetInAtom = ref->offsetInAtom();
Nick Kledzike5552772013-12-19 21:58:00 +0000436 nref.kindNamespace = (uint8_t)ref->kindNamespace();
437 nref.kindArch = (uint8_t)ref->kindArch();
438 nref.kindValue = ref->kindValue();
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000439 nref.targetIndex = this->getTargetIndex(ref->target());
Rui Ueyamae05b6292013-11-20 20:54:18 +0000440 nref.addend = ref->addend();
441 _referencesV2.push_back(nref);
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000442 }
Rui Ueyamae05b6292013-11-20 20:54:18 +0000443 refsCount = _referencesV2.size() - startRefSize;
Rui Ueyamae4d20ab2013-11-16 01:01:35 +0000444 return (refsCount == 0) ? 0 : result;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000445 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000446
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000447 uint32_t getTargetIndex(const Atom* target) {
Nick Kledzikb334be12012-04-07 01:31:00 +0000448 if ( target == nullptr )
Rui Ueyamae05b6292013-11-20 20:54:18 +0000449 return NativeReferenceIvarsV2::noTarget;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000450 TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
451 if ( pos != _targetsTableIndex.end() ) {
452 return pos->second;
453 }
Nick Kledzikabb69812012-05-31 22:34:00 +0000454 uint32_t result = _targetsTableIndex.size();
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000455 _targetsTableIndex[target] = result;
456 return result;
457 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000458
459 void writeTargetTable(raw_ostream &out) {
460 // Build table of target indexes
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000461 uint32_t maxTargetIndex = _targetsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000462 assert(maxTargetIndex > 0);
463 std::vector<uint32_t> targetIndexes(maxTargetIndex);
Rui Ueyama12027e52013-11-15 23:53:32 +0000464 for (auto &it : _targetsTableIndex) {
465 const Atom* atom = it.first;
466 uint32_t targetIndex = it.second;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000467 assert(targetIndex < maxTargetIndex);
Rui Ueyama5dcabbc2013-11-16 01:14:37 +0000468
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000469 TargetToIndex::iterator pos = _definedAtomIndex.find(atom);
Rui Ueyama5dcabbc2013-11-16 01:14:37 +0000470 if (pos != _definedAtomIndex.end()) {
471 targetIndexes[targetIndex] = pos->second;
472 continue;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000473 }
Rui Ueyama5dcabbc2013-11-16 01:14:37 +0000474 uint32_t base = _definedAtomIvars.size();
475
476 pos = _undefinedAtomIndex.find(atom);
477 if (pos != _undefinedAtomIndex.end()) {
478 targetIndexes[targetIndex] = pos->second + base;
479 continue;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000480 }
Rui Ueyama5dcabbc2013-11-16 01:14:37 +0000481 base += _undefinedAtomIndex.size();
482
483 pos = _sharedLibraryAtomIndex.find(atom);
484 if (pos != _sharedLibraryAtomIndex.end()) {
485 targetIndexes[targetIndex] = pos->second + base;
486 continue;
487 }
488 base += _sharedLibraryAtomIndex.size();
489
490 pos = _absoluteAtomIndex.find(atom);
491 assert(pos != _absoluteAtomIndex.end());
492 targetIndexes[targetIndex] = pos->second + base;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000493 }
494 // write table
Rui Ueyama5dcabbc2013-11-16 01:14:37 +0000495 out.write((char*)&targetIndexes[0], maxTargetIndex * sizeof(uint32_t));
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000496 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000497
498 uint32_t getAddendIndex(Reference::Addend addend) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000499 if ( addend == 0 )
500 return 0; // addend index zero is used to mean "no addend"
501 AddendToIndex::const_iterator pos = _addendsTableIndex.find(addend);
502 if ( pos != _addendsTableIndex.end() ) {
503 return pos->second;
504 }
505 uint32_t result = _addendsTableIndex.size() + 1; // one-based index
506 _addendsTableIndex[addend] = result;
507 return result;
508 }
Michael J. Spencer765792d2012-04-03 18:40:27 +0000509
Michael J. Spencere6203a52012-04-03 18:39:40 +0000510 void writeAddendTable(raw_ostream &out) {
Michael J. Spencer765792d2012-04-03 18:40:27 +0000511 // Build table of addends
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000512 uint32_t maxAddendIndex = _addendsTableIndex.size();
Michael J. Spencer4ff3c792012-03-09 05:26:55 +0000513 std::vector<Reference::Addend> addends(maxAddendIndex);
Rui Ueyama12027e52013-11-15 23:53:32 +0000514 for (auto &it : _addendsTableIndex) {
515 Reference::Addend addend = it.first;
516 uint32_t index = it.second;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000517 assert(index <= maxAddendIndex);
518 addends[index-1] = addend;
519 }
520 // write table
521 out.write((char*)&addends[0], maxAddendIndex*sizeof(Reference::Addend));
522 }
523
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000524 typedef std::vector<std::pair<StringRef, uint32_t>> NameToOffsetVector;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000525
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000526 typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex;
527 typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex;
528
Nick Kledzik23384e82012-02-07 02:59:54 +0000529 NativeFileHeader* _headerBuffer;
530 size_t _headerBufferSize;
531 std::vector<char> _stringPool;
532 std::vector<uint8_t> _contentPool;
533 std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
534 std::vector<NativeAtomAttributesV1> _attributes;
Sid Manning2a590242012-10-18 17:16:19 +0000535 std::vector<NativeAtomAttributesV1> _absAttributes;
Nick Kledzik23384e82012-02-07 02:59:54 +0000536 std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000537 std::vector<NativeSharedLibraryAtomIvarsV1> _sharedLibraryAtomIvars;
538 std::vector<NativeAbsoluteAtomIvarsV1> _absoluteAtomIvars;
Rui Ueyamae05b6292013-11-20 20:54:18 +0000539 std::vector<NativeReferenceIvarsV1> _referencesV1;
540 std::vector<NativeReferenceIvarsV2> _referencesV2;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000541 TargetToIndex _targetsTableIndex;
542 TargetToIndex _definedAtomIndex;
543 TargetToIndex _undefinedAtomIndex;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000544 TargetToIndex _sharedLibraryAtomIndex;
545 TargetToIndex _absoluteAtomIndex;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000546 AddendToIndex _addendsTableIndex;
Nick Kledzik23384e82012-02-07 02:59:54 +0000547 NameToOffsetVector _sectionNames;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000548 NameToOffsetVector _sharedLibraryNames;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000549};
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000550} // end namespace native
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000551
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000552std::unique_ptr<Writer> createWriterNative(const LinkingContext &context) {
553 return std::unique_ptr<Writer>(new native::Writer(context));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000554}
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000555} // end namespace lld