blob: e9533be636cfb07cc07154c678465924d284027b [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));
47 if (!_contentPool.empty())
48 out.write((char*)&_contentPool[0], _contentPool.size());
49 if (!_stringPool.empty())
50 out.write(&_stringPool[0], _stringPool.size());
Nick Kledzik55fd6be2012-01-16 22:03:44 +000051 }
52
53private:
54
55 // visitor routine called by forEachAtom()
56 virtual void doDefinedAtom(const class DefinedAtom& atom) {
57 NativeDefinedAtomIvarsV1 ivar;
58 ivar.nameOffset = getNameOffset(atom);
59 ivar.attributesOffset = getAttributeOffset(atom);
60 ivar.contentOffset = getContentOffset(atom);
61 ivar.contentSize = atom.size();
62 _definedAtomIvars.push_back(ivar);
63 }
64
65 // visitor routine called by forEachAtom()
66 virtual void doUndefinedAtom(const class UndefinedAtom& atom) {
67 }
68
69 // visitor routine called by forEachAtom()
70 virtual void doFile(const class File &) {
71 }
72
73 // fill out native file header and chunk directory
74 void makeHeader() {
75 _headerBufferSize = sizeof(NativeFileHeader) + 4*sizeof(NativeChunk);
76 _headerBuffer = reinterpret_cast<NativeFileHeader*>
77 (operator new(_headerBufferSize, std::nothrow));
Michael J. Spencerb2bd7332012-01-31 21:45:53 +000078 NativeChunk *chunks =
79 reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
80 + sizeof(NativeFileHeader));
Nick Kledzik55fd6be2012-01-16 22:03:44 +000081 memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC, 16);
82 _headerBuffer->endian = NFH_LittleEndian;
83 _headerBuffer->architecture = 0;
84 _headerBuffer->fileSize = 0;
85 _headerBuffer->chunkCount = 4;
86
87 // create chunk for atom ivar array
Michael J. Spencerb2bd7332012-01-31 21:45:53 +000088 NativeChunk& ch0 = chunks[0];
Nick Kledzik55fd6be2012-01-16 22:03:44 +000089 ch0.signature = NCS_DefinedAtomsV1;
90 ch0.fileOffset = _headerBufferSize;
91 ch0.fileSize = _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1);
92 ch0.elementCount = _definedAtomIvars.size();
Michael J. Spencerb2bd7332012-01-31 21:45:53 +000093 // create chunk for attributes
94 NativeChunk& ch1 = chunks[1];
Nick Kledzik55fd6be2012-01-16 22:03:44 +000095 ch1.signature = NCS_AttributesArrayV1;
96 ch1.fileOffset = ch0.fileOffset + ch0.fileSize;
97 ch1.fileSize = _attributes.size()*sizeof(NativeAtomAttributesV1);
98 ch1.elementCount = _attributes.size();
Michael J. Spencerb2bd7332012-01-31 21:45:53 +000099 // create chunk for content
100 NativeChunk& ch2 = chunks[2];
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000101 ch2.signature = NCS_Content;
102 ch2.fileOffset = ch1.fileOffset + ch1.fileSize;
103 ch2.fileSize = _contentPool.size();
104 ch2.elementCount = _contentPool.size();
105 // create chunk for symbol strings
Michael J. Spencerb2bd7332012-01-31 21:45:53 +0000106 NativeChunk& ch3 = chunks[3];
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000107 ch3.signature = NCS_Strings;
108 ch3.fileOffset = ch2.fileOffset + ch2.fileSize;
109 ch3.fileSize = _stringPool.size();
110 ch3.elementCount = _stringPool.size();
111
112 _headerBuffer->fileSize = ch3.fileOffset + ch3.fileSize;
113 }
114
115
116 // append atom name to string pool and return offset
117 uint32_t getNameOffset(const class DefinedAtom& atom) {
118 return this->getNameOffset(atom.name());
119 }
120
121 // append atom name to string pool and return offset
122 uint32_t getNameOffset(llvm::StringRef name) {
123 uint32_t result = _stringPool.size();
124 _stringPool.insert(_stringPool.end(), name.size()+1, 0);
125 strcpy(&_stringPool[result], name.data());
126 return result;
127 }
128
129 // append atom cotent to content pool and return offset
130 uint32_t getContentOffset(const class DefinedAtom& atom) {
131 if ( atom.contentType() == DefinedAtom::typeZeroFill )
132 return 0;
133 uint32_t result = _contentPool.size();
134 llvm::ArrayRef<uint8_t> cont = atom.rawContent();
Michael J. Spencer846fe662012-01-31 21:46:05 +0000135 _contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000136 return result;
137 }
138
139 // reuse existing attributes entry or create a new one and return offet
140 uint32_t getAttributeOffset(const class DefinedAtom& atom) {
141 NativeAtomAttributesV1 attrs;
142 computeAttributesV1(atom, attrs);
143 for(unsigned int i=0; i < _attributes.size(); ++i) {
144 if ( !memcmp(&_attributes[i], &attrs, sizeof(NativeAtomAttributesV1)) ) {
145 // found that this set of attributes already used, so re-use
146 return i * sizeof(NativeAtomAttributesV1);
147 }
148 }
149 // append new attribute set to end
150 uint32_t result = _attributes.size() * sizeof(NativeAtomAttributesV1);
151 _attributes.push_back(attrs);
152 return result;
153 }
154
155 uint32_t sectionNameOffset(const class DefinedAtom& atom) {
156 // if section based on content, then no custom section name available
157 if ( atom.sectionChoice() == DefinedAtom::sectionBasedOnContent )
158 return 0;
159 llvm::StringRef name = atom.customSectionName();
160 assert( ! name.empty() );
161 // look to see if this section name was used by another atom
162 for(NameToOffsetVector::iterator it=_sectionNames.begin();
163 it != _sectionNames.end(); ++it) {
164 if ( name.equals(it->first) )
165 return it->second;
166 }
167 // first use of this section name
168 uint32_t result = this->getNameOffset(name);
169 _sectionNames.push_back(
170 std::make_pair<llvm::StringRef, uint32_t>(name, result));
171 return result;
172 }
173
174 void computeAttributesV1(const class DefinedAtom& atom,
175 NativeAtomAttributesV1& attrs) {
176 attrs.sectionNameOffset = sectionNameOffset(atom);
177 attrs.align2 = atom.alignment().powerOf2;
178 attrs.alignModulus = atom.alignment().modulus;
179 attrs.internalName = atom.internalName();
180 attrs.scope = atom.scope();
181 attrs.interposable = atom.interposable();
182 attrs.merge = atom.merge();
183 attrs.contentType = atom.contentType();
184 attrs.sectionChoice = atom.sectionChoice();
185 attrs.deadStrip = atom.deadStrip();
186 attrs.permissions = atom.permissions();
187 attrs.thumb = atom.isThumb();
188 attrs.alias = atom.isAlias();
189 }
190
191 typedef std::vector<std::pair<llvm::StringRef, uint32_t> > NameToOffsetVector;
192
193 const lld::File& _file;
194 NativeFileHeader* _headerBuffer;
195 size_t _headerBufferSize;
196 std::vector<char> _stringPool;
197 std::vector<uint8_t> _contentPool;
198 std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
199 std::vector<NativeAtomAttributesV1> _attributes;
200 NameToOffsetVector _sectionNames;
201};
202
203
204
205
206
207/// writeNativeObjectFile - writes the lld::File object in native object
208/// file format to the specified stream.
209int writeNativeObjectFile(const lld::File &file, llvm::raw_ostream &out) {
210 NativeWriter writer(file);
211 writer.write(out);
212 return 0;
213}
214
215/// writeNativeObjectFile - writes the lld::File object in native object
216/// file format to the specified file path.
217int writeNativeObjectFile(const lld::File& file, llvm::StringRef path) {
218 std::string errorInfo;
219 llvm::raw_fd_ostream out(path.data(), errorInfo, llvm::raw_fd_ostream::F_Binary);
220 if ( !errorInfo.empty() )
221 return -1;
222 return writeNativeObjectFile(file, out);
223}
224
225} // namespace lld