blob: 09fdd9cdd17a2175db22ff447fe3e516c39ac6af [file] [log] [blame]
Nick Kledzik55fd6be2012-01-16 22:03:44 +00001//===- Core/NativeWriter.cpp - Creates a native object file ---------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include <vector>
11#include <map>
12
13#include "llvm/ADT/StringRef.h"
14#include "llvm/ADT/ArrayRef.h"
15
16#include "lld/Core/File.h"
17#include "lld/Core/NativeWriter.h"
18
19#include "NativeFileFormat.h"
20
21
22namespace lld {
23
24
25///
26/// Class for writing native object files.
27///
28class NativeWriter : public File::AtomHandler {
29public:
30 /// construct writer for an lld::File object
31 NativeWriter(const lld::File& file) : _file(file) {
32 // visit all atoms
33 _file.forEachAtom(*this);
34 // construct file header based on atom information accumulated
35 makeHeader();
36 }
37
38 // write the lld::File in native format to the specified stream
39 void write(llvm::raw_ostream& out) {
40 out.write((char*)_headerBuffer, _headerBufferSize);
Michael J. Spencer8c36f452012-01-31 21:46:41 +000041 if (!_definedAtomIvars.empty())
42 out.write((char*)&_definedAtomIvars[0],
43 _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1));
44 if (!_attributes.empty())
45 out.write((char*)&_attributes[0],
46 _attributes.size()*sizeof(NativeAtomAttributesV1));
Nick Kledzik23384e82012-02-07 02:59:54 +000047 if ( !_undefinedAtomIvars.empty() )
48 out.write((char*)&_undefinedAtomIvars[0],
49 _undefinedAtomIvars.size()*sizeof(NativeUndefinedAtomIvarsV1));
Michael J. Spencer8c36f452012-01-31 21:46:41 +000050 if (!_stringPool.empty())
51 out.write(&_stringPool[0], _stringPool.size());
Nick Kledzik23384e82012-02-07 02:59:54 +000052 if (!_contentPool.empty())
53 out.write((char*)&_contentPool[0], _contentPool.size());
Nick Kledzik55fd6be2012-01-16 22:03:44 +000054 }
55
56private:
57
58 // visitor routine called by forEachAtom()
59 virtual void doDefinedAtom(const class DefinedAtom& atom) {
60 NativeDefinedAtomIvarsV1 ivar;
61 ivar.nameOffset = getNameOffset(atom);
62 ivar.attributesOffset = getAttributeOffset(atom);
63 ivar.contentOffset = getContentOffset(atom);
64 ivar.contentSize = atom.size();
65 _definedAtomIvars.push_back(ivar);
66 }
67
68 // visitor routine called by forEachAtom()
69 virtual void doUndefinedAtom(const class UndefinedAtom& atom) {
Nick Kledzik23384e82012-02-07 02:59:54 +000070 NativeUndefinedAtomIvarsV1 ivar;
71 ivar.nameOffset = getNameOffset(atom);
72 ivar.flags = (atom.weakImport() ? 1 : 0);
73 _undefinedAtomIvars.push_back(ivar);
Nick Kledzik55fd6be2012-01-16 22:03:44 +000074 }
75
76 // visitor routine called by forEachAtom()
77 virtual void doFile(const class File &) {
78 }
Nick Kledzik23384e82012-02-07 02:59:54 +000079
Nick Kledzik55fd6be2012-01-16 22:03:44 +000080 // fill out native file header and chunk directory
81 void makeHeader() {
Nick Kledzik23384e82012-02-07 02:59:54 +000082 const bool hasUndefines = !_undefinedAtomIvars.empty();
83 const int chunkCount = hasUndefines ? 5 : 4;
84 _headerBufferSize = sizeof(NativeFileHeader)
85 + chunkCount*sizeof(NativeChunk);
Nick Kledzik55fd6be2012-01-16 22:03:44 +000086 _headerBuffer = reinterpret_cast<NativeFileHeader*>
87 (operator new(_headerBufferSize, std::nothrow));
Michael J. Spencerb2bd7332012-01-31 21:45:53 +000088 NativeChunk *chunks =
89 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
90 + sizeof(NativeFileHeader));
Nick Kledzik55fd6be2012-01-16 22:03:44 +000091 memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC, 16);
92 _headerBuffer->endian = NFH_LittleEndian;
93 _headerBuffer->architecture = 0;
94 _headerBuffer->fileSize = 0;
Nick Kledzik23384e82012-02-07 02:59:54 +000095 _headerBuffer->chunkCount = chunkCount;
96
Nick Kledzik55fd6be2012-01-16 22:03:44 +000097
98 // create chunk for atom ivar array
Nick Kledzik23384e82012-02-07 02:59:54 +000099 int nextIndex = 0;
100 NativeChunk& chd = chunks[nextIndex++];
101 chd.signature = NCS_DefinedAtomsV1;
102 chd.fileOffset = _headerBufferSize;
103 chd.fileSize = _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1);
104 chd.elementCount = _definedAtomIvars.size();
105 uint32_t nextFileOffset = chd.fileOffset + chd.fileSize;
106
107 // create chunk for attributes
108 NativeChunk& cha = chunks[nextIndex++];
109 cha.signature = NCS_AttributesArrayV1;
110 cha.fileOffset = nextFileOffset;
111 cha.fileSize = _attributes.size()*sizeof(NativeAtomAttributesV1);
112 cha.elementCount = _attributes.size();
113 nextFileOffset = cha.fileOffset + cha.fileSize;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000114
Nick Kledzik23384e82012-02-07 02:59:54 +0000115 // create chunk for undefined atom array
116 if ( hasUndefines ) {
117 NativeChunk& chu = chunks[nextIndex++];
118 chu.signature = NCS_UndefinedAtomsV1;
119 chu.fileOffset = nextFileOffset;
120 chu.fileSize = _undefinedAtomIvars.size() *
121 sizeof(NativeUndefinedAtomIvarsV1);
122 chu.elementCount = _undefinedAtomIvars.size();
123 nextFileOffset = chu.fileOffset + chu.fileSize;
124 }
125
126 // create chunk for symbol strings
127 NativeChunk& chs = chunks[nextIndex++];
128 chs.signature = NCS_Strings;
129 chs.fileOffset = nextFileOffset;
130 chs.fileSize = _stringPool.size();
131 chs.elementCount = _stringPool.size();
132 nextFileOffset = chs.fileOffset + chs.fileSize;
133
134 // create chunk for content
135 NativeChunk& chc = chunks[nextIndex++];
136 chc.signature = NCS_Content;
137 chc.fileOffset = nextFileOffset;
138 chc.fileSize = _contentPool.size();
139 chc.elementCount = _contentPool.size();
140 nextFileOffset = chc.fileOffset + chc.fileSize;
141
142 _headerBuffer->fileSize = nextFileOffset;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000143 }
144
145
146 // append atom name to string pool and return offset
Nick Kledzik23384e82012-02-07 02:59:54 +0000147 uint32_t getNameOffset(const Atom& atom) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000148 return this->getNameOffset(atom.name());
149 }
150
151 // append atom name to string pool and return offset
152 uint32_t getNameOffset(llvm::StringRef name) {
153 uint32_t result = _stringPool.size();
154 _stringPool.insert(_stringPool.end(), name.size()+1, 0);
155 strcpy(&_stringPool[result], name.data());
156 return result;
157 }
158
159 // append atom cotent to content pool and return offset
160 uint32_t getContentOffset(const class DefinedAtom& atom) {
161 if ( atom.contentType() == DefinedAtom::typeZeroFill )
162 return 0;
163 uint32_t result = _contentPool.size();
164 llvm::ArrayRef<uint8_t> cont = atom.rawContent();
Michael J. Spencer846fe662012-01-31 21:46:05 +0000165 _contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000166 return result;
167 }
168
169 // reuse existing attributes entry or create a new one and return offet
170 uint32_t getAttributeOffset(const class DefinedAtom& atom) {
171 NativeAtomAttributesV1 attrs;
172 computeAttributesV1(atom, attrs);
173 for(unsigned int i=0; i < _attributes.size(); ++i) {
174 if ( !memcmp(&_attributes[i], &attrs, sizeof(NativeAtomAttributesV1)) ) {
175 // found that this set of attributes already used, so re-use
176 return i * sizeof(NativeAtomAttributesV1);
177 }
178 }
179 // append new attribute set to end
180 uint32_t result = _attributes.size() * sizeof(NativeAtomAttributesV1);
181 _attributes.push_back(attrs);
182 return result;
183 }
184
185 uint32_t sectionNameOffset(const class DefinedAtom& atom) {
186 // if section based on content, then no custom section name available
187 if ( atom.sectionChoice() == DefinedAtom::sectionBasedOnContent )
188 return 0;
189 llvm::StringRef name = atom.customSectionName();
190 assert( ! name.empty() );
191 // look to see if this section name was used by another atom
192 for(NameToOffsetVector::iterator it=_sectionNames.begin();
193 it != _sectionNames.end(); ++it) {
194 if ( name.equals(it->first) )
195 return it->second;
196 }
197 // first use of this section name
198 uint32_t result = this->getNameOffset(name);
199 _sectionNames.push_back(
200 std::make_pair<llvm::StringRef, uint32_t>(name, result));
201 return result;
202 }
203
204 void computeAttributesV1(const class DefinedAtom& atom,
205 NativeAtomAttributesV1& attrs) {
206 attrs.sectionNameOffset = sectionNameOffset(atom);
207 attrs.align2 = atom.alignment().powerOf2;
208 attrs.alignModulus = atom.alignment().modulus;
209 attrs.internalName = atom.internalName();
210 attrs.scope = atom.scope();
211 attrs.interposable = atom.interposable();
212 attrs.merge = atom.merge();
213 attrs.contentType = atom.contentType();
214 attrs.sectionChoice = atom.sectionChoice();
215 attrs.deadStrip = atom.deadStrip();
216 attrs.permissions = atom.permissions();
217 attrs.thumb = atom.isThumb();
218 attrs.alias = atom.isAlias();
219 }
220
221 typedef std::vector<std::pair<llvm::StringRef, uint32_t> > NameToOffsetVector;
222
Nick Kledzik23384e82012-02-07 02:59:54 +0000223 const lld::File& _file;
224 NativeFileHeader* _headerBuffer;
225 size_t _headerBufferSize;
226 std::vector<char> _stringPool;
227 std::vector<uint8_t> _contentPool;
228 std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
229 std::vector<NativeAtomAttributesV1> _attributes;
230 std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
231 NameToOffsetVector _sectionNames;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000232};
233
234
235
236
237
238/// writeNativeObjectFile - writes the lld::File object in native object
239/// file format to the specified stream.
240int writeNativeObjectFile(const lld::File &file, llvm::raw_ostream &out) {
241 NativeWriter writer(file);
242 writer.write(out);
243 return 0;
244}
245
246/// writeNativeObjectFile - writes the lld::File object in native object
247/// file format to the specified file path.
248int writeNativeObjectFile(const lld::File& file, llvm::StringRef path) {
249 std::string errorInfo;
250 llvm::raw_fd_ostream out(path.data(), errorInfo, llvm::raw_fd_ostream::F_Binary);
251 if ( !errorInfo.empty() )
252 return -1;
253 return writeNativeObjectFile(file, out);
254}
255
256} // namespace lld