blob: 974e82975f7630c99711533a4f3b49b65a8821db [file] [log] [blame]
Nick Kledzikabb69812012-05-31 22:34:00 +00001//===- lib/ReaderWriter/ELF/WriterELF.cpp ---------------------------------===//
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 "lld/ReaderWriter/WriterELF.h"
Hemant Kulkarni927bbc22012-09-14 16:11:34 +000011#include "ReferenceKinds.h"
Nick Kledzikabb69812012-05-31 22:34:00 +000012
Hemant Kulkarni927bbc22012-09-14 16:11:34 +000013#include "lld/Core/DefinedAtom.h"
14#include "lld/Core/File.h"
15#include "lld/Core/InputFiles.h"
16#include "lld/Core/Reference.h"
17#include "lld/Core/SharedLibraryAtom.h"
18
19#include "llvm/ADT/ArrayRef.h"
20#include "llvm/ADT/DenseMap.h"
21#include "llvm/ADT/OwningPtr.h"
22#include "llvm/ADT/SmallVector.h"
23#include "llvm/ADT/StringMap.h"
24#include "llvm/ADT/StringRef.h"
25
26#include "llvm/Object/ELF.h"
27
28#include "llvm/Support/Allocator.h"
Nick Kledzikabb69812012-05-31 22:34:00 +000029#include "llvm/Support/Debug.h"
Hemant Kulkarni927bbc22012-09-14 16:11:34 +000030#include "llvm/Support/ELF.h"
31#include "llvm/Support/ErrorHandling.h"
32#include "llvm/Support/FileOutputBuffer.h"
33#include "llvm/Support/Format.h"
34#include "llvm/Support/MathExtras.h"
35#include "llvm/Support/raw_ostream.h"
36#include "llvm/Support/system_error.h"
Nick Kledzikabb69812012-05-31 22:34:00 +000037
Hemant Kulkarni927bbc22012-09-14 16:11:34 +000038#include <map>
39#include <tuple>
40#include <vector>
Nick Kledzikabb69812012-05-31 22:34:00 +000041
Hemant Kulkarni927bbc22012-09-14 16:11:34 +000042using namespace llvm;
43using namespace llvm::object;
Nick Kledzikabb69812012-05-31 22:34:00 +000044namespace lld {
45namespace elf {
46
Hemant Kulkarni927bbc22012-09-14 16:11:34 +000047template<support::endianness target_endianness, bool is64Bits>
48class ELFWriter;
Nick Kledzikabb69812012-05-31 22:34:00 +000049
Hemant Kulkarni927bbc22012-09-14 16:11:34 +000050/// \brief A Chunk is a contiguous range of space.
51template<support::endianness target_endianness, bool is64Bits>
52class Chunk {
53public:
54 LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
55 virtual ~Chunk() {}
56 virtual StringRef segmentName() const = 0;
57 virtual bool occupiesNoDiskSpace();
58 virtual void write(uint8_t *fileBuffer) = 0;
59 void assignFileOffset(uint64_t &curOff, uint64_t &curAddr);
60 virtual const char *info() = 0;
61 uint64_t size() const;
62 uint64_t address() const;
63 uint64_t fileOffset() const;
64 uint64_t align2() const;
65 static uint64_t alignTo(uint64_t value, uint8_t align2);
Hemant Kulkarni08e410292012-10-01 23:53:20 +000066 uint64_t ordinal() const { return _ordinal;}
67 void setOrdinal(uint64_t newVal) { _ordinal = newVal;}
Hemant Kulkarni927bbc22012-09-14 16:11:34 +000068
69protected:
70 Chunk();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +000071 uint64_t _size;
72 uint64_t _address;
73 uint64_t _fileOffset;
74 uint64_t _align2;
Hemant Kulkarni08e410292012-10-01 23:53:20 +000075 uint64_t _ordinal;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +000076};
77
Hemant Kulkarni08e410292012-10-01 23:53:20 +000078template<support::endianness target_endianness, bool is64Bits>
79static void swapChunkPositions(Chunk<target_endianness, is64Bits>&a,
80 Chunk<target_endianness, is64Bits>&b) {
81 uint64_t tempOrdinal;
82 if (a.ordinal() == b.ordinal()) return;
83 tempOrdinal = a.ordinal();
84 a.setOrdinal(b.ordinal());
85 b.setOrdinal(tempOrdinal);
86}
87
Hemant Kulkarni927bbc22012-09-14 16:11:34 +000088/// Pair of atom and offset in section.
89typedef std::tuple<const DefinedAtom*, uint64_t> AtomInfo;
90
Hemant Kulkarni08e410292012-10-01 23:53:20 +000091/// \brief A SectionChunk represents ELF sections
Hemant Kulkarni927bbc22012-09-14 16:11:34 +000092template<support::endianness target_endianness, bool is64Bits>
93class SectionChunk : public Chunk<target_endianness, is64Bits> {
94public:
Hemant Kulkarni08e410292012-10-01 23:53:20 +000095 virtual StringRef segmentName() const { return _segmentName; }
96 virtual bool occupiesNoDiskSpace();
97 virtual const char *info();
98 StringRef sectionName() { return _sectionName; }
99 uint64_t shStrtableOffset(){ return _offsetInStringTable; }
100 void setShStrtableOffset (uint64_t val) {
101 _offsetInStringTable = val; }
102 uint32_t flags() { return _flags; }
103 uint32_t type() { return _type; }
104 uint64_t link() { return _link; }
105 void link(uint64_t val) { _link = val; }
106 uint16_t shinfo() { return _shinfo; }
107 bool isLoadable() { return _isLoadable; }
108 void isLoadable(uint64_t val) { _isLoadable = val; }
109 uint64_t entsize() { return _entsize; }
110 SectionChunk(StringRef secName, StringRef segName, bool loadable,
111 uint64_t flags , uint64_t link, uint64_t info ,
112 uint64_t type, uint64_t entsz, const WriterOptionsELF &op,
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000113 ELFWriter<target_endianness, is64Bits> &writer);
114
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000115protected:
116 bool _isLoadable;
117 uint64_t _link;
118 uint64_t _shinfo;
119 uint16_t _entsize;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000120 StringRef _segmentName;
121 StringRef _sectionName;
122 const WriterOptionsELF &_options;
123 ELFWriter<target_endianness, is64Bits> &_writer;
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000124 uint64_t _flags;
125 uint64_t _type;
126 uint64_t _offsetInStringTable;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000127};
128
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000129/// \brief A StockSectionChunk is a section created by linker with all
130/// attributes concluded from the defined atom contained within.
131template<support::endianness target_endianness, bool is64Bits>
132class StockSectionChunk : public SectionChunk<target_endianness, is64Bits> {
133public:
134 virtual StringRef segmentName() { return this->_segmentName; }
135 void appendAtom(const DefinedAtom*);
136 virtual void write(uint8_t *filebuffer);
137 const ArrayRef<AtomInfo> atoms() const;
138 StockSectionChunk(StringRef sectionName, bool loadable,
139 DefinedAtom::ContentType type,
140 const WriterOptionsELF &options,
141 ELFWriter<target_endianness, is64Bits> &writer);
142private:
143 std::vector<AtomInfo> _atoms;
144};
145
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000146/// \brief An ELFHeaderChunk represents the Elf[32/64]_Ehdr structure at the
147/// start of an ELF executable file.
148template<support::endianness target_endianness, bool is64Bits>
149class ELFHeaderChunk : public Chunk<target_endianness, is64Bits> {
150public:
151 LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
152 typedef object::Elf_Ehdr_Impl<target_endianness, is64Bits> Elf_Ehdr;
153
154 ELFHeaderChunk(const WriterOptionsELF &options,
155 const File &file);
156
157 void e_ident(int I, unsigned char C) { _eh.e_ident[I] = C; }
158 void e_type(uint16_t type) { _eh.e_type = type; }
159 void e_machine(uint16_t machine) { _eh.e_machine = machine; }
160 void e_version(uint32_t version) { _eh.e_version = version; }
161 void e_entry(uint64_t entry) { _eh.e_entry = entry; }
162 void e_phoff(uint64_t phoff) { _eh.e_phoff = phoff; }
163 void e_shoff(uint64_t shoff) { _eh.e_shoff = shoff; }
164 void e_flags(uint32_t flags) { _eh.e_flags = flags; }
165 void e_ehsize(uint16_t ehsize) { _eh.e_ehsize = ehsize; }
166 void e_phentsize(uint16_t phentsize) { _eh.e_phentsize = phentsize; }
167 void e_phnum(uint16_t phnum) { _eh.e_phnum = phnum; }
168 void e_shentsize(uint16_t shentsize) { _eh.e_shentsize = shentsize; }
169 void e_shnum(uint16_t shnum) { _eh.e_shnum = shnum; }
170 void e_shstrndx(uint16_t shstrndx) { _eh.e_shstrndx = shstrndx; }
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000171 uint64_t size() { return sizeof (Elf_Ehdr); }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000172
173 virtual StringRef segmentName() const;
174 virtual void write(uint8_t *fileBuffer);
175 virtual const char *info();
176
177private:
178 Elf_Ehdr _eh;
179};
180
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000181/// \brief An ELFSectionHeaderChunk represents the Elf[32/64]_Shdr structure
182/// that is placed right after the ELFHeader.
183///
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000184template<support::endianness target_endianness, bool is64Bits>
185class ELFSectionHeaderChunk : public Chunk<target_endianness, is64Bits> {
186public:
187 LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
188 typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
189 ELFSectionHeaderChunk(const WriterOptionsELF &Options,
190 ELFWriter<target_endianness, is64Bits>&);
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000191 void createHeaders();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000192 virtual StringRef segmentName() const;
193 virtual void write(uint8_t *filebuffer);
194 virtual const char *info();
195 void computeSize(const lld::File &file);
196 uint16_t count();
197 uint16_t size();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000198 const ArrayRef<Elf_Shdr*> sectionInfo() {
199 return _sectionInfo;
200 }
201
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000202private:
203 const WriterOptionsELF &_options;
204 ELFWriter<target_endianness, is64Bits> &_writer;
205 llvm::BumpPtrAllocator _sectionAllocate;
206 std::vector<Elf_Shdr*> _sectionInfo;
207};
208
209/// \brief Represents the shstr section.
210///
211/// This is a contiguous memory that has all the symbol strings each ending with
212/// null character. We might need more than one such chunks shstrtab for setting
213/// e_shstrndx in ELHHeaderChunk and strtab for use with symtab
214template<support::endianness target_endianness, bool is64Bits>
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000215class ELFStringSectionChunk : public SectionChunk<target_endianness, is64Bits> {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000216public:
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000217 ELFStringSectionChunk(const WriterOptionsELF &Options,
218 ELFWriter<target_endianness, is64Bits> &writer,
219 StringRef secName);
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000220 virtual StringRef segmentName() const { return this->_segmentName; }
221 uint64_t addString(StringRef symName);
222 const char *info();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000223 virtual void write(uint8_t *filebuffer);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000224
225private:
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000226 std::vector<StringRef> _stringSection;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000227};
228
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000229/// \brief Represents the symtab section
230///
231/// ELFSymbolTableChunk represents the Symbol table as per ELF ABI
232/// This is a table with Elf[32/64]_Sym entries in it.
233template<support::endianness target_endianness, bool is64Bits>
234class ELFSymbolTableChunk : public SectionChunk<target_endianness, is64Bits> {
235public:
236 typedef object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
237 ELFSymbolTableChunk(const WriterOptionsELF &options,
238 ELFWriter<target_endianness, is64Bits> &writer,
239 StringRef secName);
240 virtual StringRef segmentName() const { return this->_segmentName; }
241 void addSymbol(const Atom *a, uint16_t shndx);
242 void addSymbol(Elf_Sym *x);
243 const char *info();
244 void setAttributes();
245 virtual void write(uint8_t *fileBuffer);
246
247private:
248 std::vector<Elf_Sym*> _symbolTable;
249 ELFStringSectionChunk<target_endianness, is64Bits> *_stringSection;
250 llvm::BumpPtrAllocator _symbolAllocate;
251};
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000252
253/// An ELFProgramHeaderChunk represents the Elf[32/64]_Phdr structure near
254/// the start of an ELF executable file. Will need to update ELFHeader's
255/// e_phentsize/e_phnum when done.
256template<support::endianness target_endianness, bool is64Bits>
257class ELFProgramHeaderChunk : public Chunk<target_endianness, is64Bits> {
258public:
259 LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
260 ELFProgramHeaderChunk(ELFHeaderChunk<target_endianness, is64Bits>&,
261 const WriterOptionsELF &options,
262 const File &file);
263
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000264 virtual StringRef segmentName() const;
265 virtual void write(uint8_t *filebuffer);
266 virtual const char *info();
267
268private:
269// TODO: Replace this with correct ELF::* type method
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000270};
271
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000272//===----------------------------------------------------------------------===//
273// Chunk
274//===----------------------------------------------------------------------===//
275
276template<support::endianness target_endianness, bool is64Bits>
277Chunk<target_endianness, is64Bits>::Chunk()
278 : _size(0), _address(0), _fileOffset(0), _align2(0) {
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000279 // 0 and 1 are reserved. 0 for ELF header and 1 for Sectiontable header.
280 static uint64_t orderNumber = 0;
281 _ordinal = orderNumber++;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000282}
283
284template<support::endianness target_endianness, bool is64Bits>
285bool Chunk<target_endianness, is64Bits>::occupiesNoDiskSpace() {
286 return false;
287}
288
289template<support::endianness target_endianness, bool is64Bits>
290uint64_t Chunk<target_endianness, is64Bits>::size() const {
291 return _size;
292}
293
294template<support::endianness target_endianness, bool is64Bits>
295uint64_t Chunk<target_endianness, is64Bits>::align2() const {
296 return _align2;
297}
298
299template<support::endianness target_endianness, bool is64Bits>
300uint64_t Chunk<target_endianness, is64Bits>::address() const {
301 return _address;
302}
303
304template<support::endianness target_endianness, bool is64Bits>
305uint64_t Chunk<target_endianness, is64Bits>::fileOffset() const {
306 return _fileOffset;
307}
308
309template<support::endianness target_endianness, bool is64Bits>
310uint64_t Chunk<target_endianness, is64Bits>::
311 alignTo(uint64_t value, uint8_t align2) {
312 uint64_t align = 1 << align2;
313 return (value + (align - 1)) & (-align);
314}
315
316template<support::endianness target_endianness, bool is64Bits>
317void Chunk<target_endianness, is64Bits>::
318 assignFileOffset(uint64_t &curOffset, uint64_t &curAddress) {
319 if (occupiesNoDiskSpace()) {
320 // FileOffset does not change, but virtual address does change.
321 uint64_t alignedAddress =
322 alignTo(curAddress, _align2 ? static_cast<uint8_t>(llvm::Log2_64(_align2))
323 : 0);
324 _address = alignedAddress;
325 curAddress = alignedAddress + _size;
326 } else {
327 // FileOffset and address both move by _size amount after alignment.
328 uint64_t alignPadding =
329 alignTo(curAddress, _align2 ? static_cast<uint8_t>(llvm::Log2_64(_align2))
330 : 0) - curAddress;
331 _fileOffset = curOffset + alignPadding;
332 _address = curAddress + alignPadding;
333 curOffset = _fileOffset + _size;
334 curAddress = _address + _size;
335 }
336
337 DEBUG_WITH_TYPE("WriterELF-layout", dbgs()
338 << " fileOffset="
339 << format("0x%08X", _fileOffset)
340 << " address="
341 << format("0x%016X", _address)
342 << " info=" << info() << "\n");
343}
344
345//===----------------------------------------------------------------------===//
346// SectionChunk
347//===----------------------------------------------------------------------===//
348
349template<support::endianness target_endianness, bool is64Bits>
350SectionChunk<target_endianness, is64Bits>::
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000351 SectionChunk(StringRef secName, StringRef segName, bool loadable,
352 uint64_t flags , uint64_t link, uint64_t info , uint64_t type,
353 uint64_t entsz, const WriterOptionsELF &op,
354 ELFWriter<target_endianness, is64Bits> &writer)
355 : _isLoadable(loadable)
356 , _link(link)
357 , _shinfo(info)
358 , _entsize(entsz)
359 , _segmentName(segName)
360 , _sectionName(secName)
361 , _options(op)
362 , _writer(writer)
363 , _flags(flags)
364 , _type(type)
365 , _offsetInStringTable(0) {}
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000366
367template<support::endianness target_endianness, bool is64Bits>
368bool SectionChunk<target_endianness, is64Bits>::occupiesNoDiskSpace() {
369 return false;
370}
371
372template<support::endianness target_endianness, bool is64Bits>
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000373const char *SectionChunk<target_endianness, is64Bits>::info() {
374 return _sectionName.data();
375}
376
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000377//===----------------------------------------------------------------------===//
378// StockSectionChunk
379//===----------------------------------------------------------------------===//
380
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000381template<support::endianness target_endianness, bool is64Bits>
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000382StockSectionChunk<target_endianness, is64Bits>::
383 StockSectionChunk(StringRef secName, bool loadable,
384 DefinedAtom::ContentType type,
385 const WriterOptionsELF &options,
386 ELFWriter<target_endianness, is64Bits> &writer)
387 : SectionChunk<target_endianness, is64Bits>(secName, "PT_NULL",
388 loadable, 0lu, 0lu, 0u, 0lu, 0lu,
389 options, writer) {
390 this->_segmentName = this->_isLoadable ? "PT_LOAD" : "PT_NULL" ;
391 switch(type) {
392 case DefinedAtom::typeCode:
393 this->_type = ELF::SHT_PROGBITS;
394 break;
395 case DefinedAtom::typeData:
396 this->_type = ELF::SHT_PROGBITS;
397 break;
398 case DefinedAtom::typeZeroFill:
399 this->_type = ELF::SHT_NOBITS;
Hemant Kulkarni8bd27612012-10-03 23:27:33 +0000400 break;
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000401 case DefinedAtom::typeConstant:
402 this->_type = ELF::SHT_PROGBITS;
403 break;
404 default:
405 llvm_unreachable("Unhandled content type for section!");
406 }
407}
408
409
410template<support::endianness target_endianness, bool is64Bits>
411const ArrayRef<AtomInfo> StockSectionChunk<target_endianness, is64Bits>::
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000412 atoms() const {
413 return _atoms;
414}
415
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000416template<support::endianness target_endianness, bool is64Bits>
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000417void StockSectionChunk<target_endianness, is64Bits>::
418 appendAtom(const DefinedAtom *atom) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000419 // Figure out offset for atom in this section given alignment constraints.
420 uint64_t offset = this->_size;
421 DefinedAtom::Alignment atomAlign = atom->alignment();
422 uint64_t align2 = 1 << atomAlign.powerOf2;
423 uint64_t requiredModulus = atomAlign.modulus;
424 uint64_t currentModulus = (offset % align2);
425 if (currentModulus != requiredModulus) {
426 if (requiredModulus > currentModulus)
427 offset += requiredModulus - currentModulus;
428 else
429 offset += align2 + requiredModulus - currentModulus;
430 }
431 // Record max alignment of any atom in this section.
432 if (align2 > this->_align2)
433 this->_align2 = align2;
434 // Assign atom to this section with this offset.
435 _atoms.emplace_back(atom, offset);
436 // Update section size to include this atom.
437 this->_size = offset + atom->size();
438 // Update permissions
439 DefinedAtom::ContentPermissions perms = atom->permissions();
440
441 // TODO: Check content permissions and figure out what to do with .bss
442 if ((perms & DefinedAtom::permR__) == DefinedAtom::permR__)
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000443 this->_flags |= ELF::SHF_ALLOC;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000444 if ((perms & DefinedAtom::permRW_) == DefinedAtom::permRW_)
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000445 this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_WRITE);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000446 if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000447 this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000448}
449
450template<support::endianness target_endianness, bool is64Bits>
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000451void StockSectionChunk<target_endianness, is64Bits>
452 ::write(uint8_t *chunkBuffer) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000453 // Each section's content is just its atoms' content.
454 for (const auto &ai : _atoms ) {
455 // Copy raw content of atom to file buffer.
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000456 ArrayRef<uint8_t> content = std::get<0>(ai)->rawContent();
457 uint64_t contentSize = content.size();
458 if (contentSize == 0)
459 continue;
460 uint8_t *atomContent = chunkBuffer + std::get<1>(ai);
461 std::copy_n(content.data(), contentSize, atomContent);
Sid Manningdd110202012-09-25 18:22:09 +0000462
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000463 for (const Reference *ref : *std::get<0>(ai)){
464 uint32_t offset = ref->offsetInAtom();
465 uint64_t targetAddress = 0;
Sid Manningdd110202012-09-25 18:22:09 +0000466
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000467 if ( ref->target() != nullptr )
468 targetAddress = this->_writer.addressOfAtom(ref->target());
Sid Manningdd110202012-09-25 18:22:09 +0000469
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000470 uint64_t fixupAddress = this->_writer.addressOfAtom(std::get<0>(ai)) +
471 offset;
472 this->_writer.kindHandler()->applyFixup(ref->kind(), ref->addend(),
473 &atomContent[offset],
474 fixupAddress,
475 targetAddress);
Sid Manningdd110202012-09-25 18:22:09 +0000476 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000477 }
478}
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000479
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000480//===----------------------------------------------------------------------===//
481// ELFStringSectionChunk
482//===----------------------------------------------------------------------===//
483template<support::endianness target_endianness, bool is64Bits>
484ELFStringSectionChunk<target_endianness, is64Bits>::
485 ELFStringSectionChunk(const WriterOptionsELF &options,
486 ELFWriter<target_endianness, is64Bits> &writer,
487 StringRef secName)
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000488 : SectionChunk<target_endianness, is64Bits>(secName, "PT_NULL",
489 false, 0lu, 0lu, 0lu,
490 ELF::SHT_STRTAB, 0lu, options,
491 writer) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000492 // First Add a null character. It also occupies 1 byte
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000493 _stringSection.emplace_back("");
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000494 this->_size = 1;
495}
496
497template<support::endianness target_endianness, bool is64Bits>
498uint64_t ELFStringSectionChunk<target_endianness, is64Bits>::
499 addString(StringRef symName) {
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000500 _stringSection.emplace_back(symName);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000501 uint64_t offset = this->_size;
502 this->_size += symName.size() + 1;
503
504 return offset;
505}
506
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000507// We need to unwrap the _stringSection and then make one large memory
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000508// chunk of null terminated strings
509template<support::endianness target_endianness, bool is64Bits>
510void ELFStringSectionChunk<target_endianness, is64Bits>::
511 write(uint8_t *chunkBuffer) {
512 uint64_t chunkOffset = 0;
513
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000514 for (auto it : _stringSection) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000515 ::memcpy(chunkBuffer + chunkOffset, it.data(), it.size());
516 chunkOffset += it.size();
517 ::memcpy(chunkBuffer + chunkOffset, "", 1);
518 chunkOffset += 1;
519 }
520}
521
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000522template<support::endianness target_endianness, bool is64Bits>
523const char *ELFStringSectionChunk<target_endianness, is64Bits>::info() {
524 return "String Table";
525}
526
527//===----------------------------------------------------------------------===//
528// ELFSymbolTableChunk
529//===----------------------------------------------------------------------===//
530template< support::endianness target_endianness, bool is64Bits>
531ELFSymbolTableChunk<target_endianness, is64Bits>::ELFSymbolTableChunk
532 (const WriterOptionsELF &options,
533 ELFWriter<target_endianness, is64Bits> &writer,
534 StringRef secName)
535 : SectionChunk<target_endianness, is64Bits>(secName, StringRef("PT_NULL"),
536 false, 0, 0, 0, ELF::SHT_SYMTAB,
537 sizeof(Elf_Sym), options, writer)
538{
539 _stringSection = this->_writer.strtab();
540 Elf_Sym *symbol = new (_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
541 memset ((void *)symbol,0, sizeof(Elf_Sym));
542 _symbolTable.push_back(symbol);
543 this->_link = 0;
544 this->_entsize = sizeof(Elf_Sym);
545 this->_size = sizeof(Elf_Sym);
546}
547
548template< support::endianness target_endianness, bool is64Bits>
549void ELFSymbolTableChunk<target_endianness, is64Bits>::addSymbol(Elf_Sym *sym){
550 _symbolTable.push_back(sym);
551 this->_size+= sizeof(Elf_Sym) ;
552}
553
554/// \brief Add symbols to symbol table
555/// We examine each property of atom to infer the various st_* fields in Elf*_Sym
556template< support::endianness target_endianness, bool is64Bits>
557void ELFSymbolTableChunk<target_endianness, is64Bits>
558 ::addSymbol(const Atom *a, uint16_t shndx) {
559 Elf_Sym *symbol = new(_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
560 unsigned char b = 0, t = 0;
561
562 symbol->st_name = _stringSection->addString(a->name());
563// In relocatable files, st_value holds a section offset for a defined symbol.
564// st_value is an offset from the beginning of the section that st_shndx
565// identifies. After we assign file offsets we can set this value correctly.
566 symbol->st_size = 0;
567 symbol->st_shndx = shndx;
568 symbol->st_value = 0;
569// FIXME: Need to change and account all STV* when visibilities are supported
570 symbol->st_other = ELF::STV_DEFAULT;
571 if (const DefinedAtom *da = llvm::dyn_cast<const DefinedAtom>(a)){
572 symbol->st_size = da->size();
573 lld::DefinedAtom::ContentType ct;
574 switch (ct = da->contentType()){
575 case DefinedAtom::typeCode:
576 t = ELF::STT_FUNC;
577 break;
578 case DefinedAtom::typeData:
579 t = ELF::STT_OBJECT;
580 break;
581 case DefinedAtom::typeZeroFill:
582 // In relocatable files, st_value holds alignment constraints for a symbol whose
583 // section index is SHN_COMMON
584 if (this->_options.type() == ELF::ET_REL){
585 t = ELF::STT_COMMON;
586 symbol->st_value = 1 << (da->alignment()).powerOf2;
587 symbol->st_shndx = ELF::SHN_COMMON;
588 }
589 break;
590 case DefinedAtom::typeFirstInSection:
591 t = ELF::STT_SECTION;
592 break;
593 // TODO:: How to find STT_FILE symbols?
594 default:
595 t = ELF::STT_NOTYPE;
596 }
597
598 if (da->scope() == DefinedAtom::scopeTranslationUnit)
599 b = ELF::STB_LOCAL;
600 else if (da->merge() == DefinedAtom::mergeAsWeak)
601 b = ELF::STB_WEAK;
602 else
603 b = ELF::STB_GLOBAL;
604 } else if (const AbsoluteAtom *aa = llvm::dyn_cast<const AbsoluteAtom>(a)){
605//FIXME: Absolute atoms need more properties to differentiate each other
606// based on binding and type of symbol
607 symbol->st_value = aa->value();
608 } else {
609 symbol->st_value = 0;
610 t = ELF::STT_NOTYPE;
611 b = ELF::STB_LOCAL;
612 }
613 symbol->setBindingAndType(b, t);
614
615 _symbolTable.push_back(symbol);
616 this->_size += sizeof(Elf_Sym);
617}
618
619template<support::endianness target_endianness, bool is64Bits>
620void ELFSymbolTableChunk<target_endianness, is64Bits>::setAttributes() {
621// sh_info should be one greater than last symbol with STB_LOCAL binding
622// we sort the symbol table to keep all local symbols at the beginning
623 std::stable_sort(_symbolTable.begin(), _symbolTable.end(), ([]
624 (const Elf_Sym *A, const Elf_Sym *B) -> bool {
625 return (A->getBinding() < B->getBinding());}));
626 uint16_t shInfo = 0;
627 for (auto i : _symbolTable) {
628 if (i->getBinding() != ELF::STB_LOCAL)
629 break;
630 shInfo++;
631 }
632 this->_shinfo = shInfo;
633// we set the associated string table index in th sh_link member
634 this->_link = this->_writer.strtab()->ordinal() - 1;
635 this->_align2 = this->_options.pointerWidth();
636}
637
638template<support::endianness target_endianness, bool is64Bits>
639const char *ELFSymbolTableChunk<target_endianness, is64Bits>::info() {
640 return "Symbol Table";
641}
642
643template<support::endianness target_endianness, bool is64Bits>
644void ELFSymbolTableChunk<target_endianness, is64Bits>::
645 write(uint8_t *chunkBuffer) {
646 uint64_t chunkOffset = 0;
647 for (auto it : _symbolTable) {
648 ::memcpy(chunkBuffer + chunkOffset, it, this->_entsize);
649 chunkOffset += this->_entsize;
650 }
651}
652
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000653//===----------------------------------------------------------------------===//
654// ELFHeaderChunk
655//===----------------------------------------------------------------------===//
656template<support::endianness target_endianness, bool is64Bits>
657ELFHeaderChunk<target_endianness, is64Bits>
658 ::ELFHeaderChunk(const WriterOptionsELF &options,
659 const File &File) {
660 this->_size = size();
661 e_ident(ELF::EI_MAG0, 0x7f);
662 e_ident(ELF::EI_MAG1, 'E');
663 e_ident(ELF::EI_MAG2, 'L');
664 e_ident(ELF::EI_MAG3, 'F');
665 e_ident(ELF::EI_CLASS, (options.is64Bit() ? ELF::ELFCLASS64
666 : ELF::ELFCLASS32));
Sid Manninge3612f02012-10-05 14:06:24 +0000667 e_ident(ELF::EI_DATA, (options.endianness() == llvm::support::big)
668 ? ELF::ELFDATA2MSB
669 : ELF::ELFDATA2LSB);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000670 e_ident(ELF::EI_VERSION, 1);
671 e_ident(ELF::EI_OSABI, ELF::ELFOSABI_NONE);
672
673 e_type(options.type());
674 e_machine(options.machine());
675 e_version(1);
676
677 e_entry(0ULL);
678 e_phoff(this->_size);
679 e_shoff(0ULL);
680
681 e_flags(0);
682 e_ehsize(this->_size);
683 e_phentsize(0);
684 e_phnum(0);
685 e_shentsize(0);
686 e_shnum(0);
687 e_shstrndx(0);
688}
689
690template<support::endianness target_endianness, bool is64Bits>
691StringRef ELFHeaderChunk<target_endianness, is64Bits>
692 ::segmentName() const {
693 return "ELF";
694}
695
696template<support::endianness target_endianness, bool is64Bits>
697void ELFHeaderChunk<target_endianness, is64Bits>
698 ::write(uint8_t *chunkBuffer) {
699 ::memcpy(chunkBuffer, &_eh, size());
700}
701
702template<support::endianness target_endianness, bool is64Bits>
703const char *ELFHeaderChunk<target_endianness, is64Bits>::info() {
704 return "elf_header";
705}
706
707//===----------------------------------------------------------------------===//
708// ELFSectionHeaderChunk
709// List of Section Headers:
710//[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
711//[ 0] NULL 00000000 000000 000000 00 0 0 0
712//[ 1] .text PROGBITS 00000000 000034 000040 00 AX 0 0 4
713//===----------------------------------------------------------------------===//
714template<support::endianness target_endianness, bool is64Bits>
715ELFSectionHeaderChunk<target_endianness, is64Bits>
716 ::ELFSectionHeaderChunk(const WriterOptionsELF& options,
717 ELFWriter<target_endianness,
718 is64Bits> &writer)
719 : _options(options)
720 , _writer(writer) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000721 this->_size = 0;
722 this->_align2 = 0;
723 // The first element in the list is always NULL
724 Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
725 ::memset(nullshdr, 0, sizeof (Elf_Shdr));
726 _sectionInfo.push_back(nullshdr);
727
728 this->_size += sizeof (Elf_Shdr);
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000729 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000730
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000731template<support::endianness target_endianness, bool is64Bits>
732void ELFSectionHeaderChunk<target_endianness, is64Bits>::createHeaders(){
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000733 ELFStringSectionChunk<target_endianness, is64Bits> *str = _writer.shstrtab();
734
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000735 for (const auto &chunk : _writer.sectionChunks()) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000736 Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
737 StringRef Name = chunk->sectionName();
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000738 if (chunk->shStrtableOffset() == 0){
739 chunk->setShStrtableOffset(str->addString(Name));
740 }
741 shdr->sh_name = chunk->shStrtableOffset();
742
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000743 shdr->sh_type = chunk->type();
744 shdr->sh_flags = chunk->flags();
745 // TODO: At the time of creation of this section header, we will not have
746 // any address and offset info. We revisit this after assigning the file
747 // offsets.
748 shdr->sh_offset = chunk->fileOffset();
749 shdr->sh_addr = chunk->address();
750 shdr->sh_size = chunk->size();
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000751 shdr->sh_link = chunk->link() ;
752 shdr->sh_info = chunk->shinfo();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000753 shdr->sh_addralign = chunk->align2();
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000754 shdr->sh_entsize = chunk->entsize();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000755
756 _sectionInfo.push_back(shdr);
757 this->_size += sizeof (Elf_Shdr);
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000758 _writer.symtab()->setAttributes();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000759 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000760}
761
762template<support::endianness target_endianness, bool is64Bits>
763StringRef ELFSectionHeaderChunk<target_endianness, is64Bits>
764 ::segmentName() const {
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000765 return "PT_NULL";
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000766}
767
768template<support::endianness target_endianness, bool is64Bits>
769void ELFSectionHeaderChunk<target_endianness, is64Bits>
770 ::write(uint8_t *chunkBuffer) {
771 for (const auto si : _sectionInfo) {
772 ::memcpy(chunkBuffer, si, sizeof(*si));
773 chunkBuffer += sizeof (*si);
774 }
775}
776
777template<support::endianness target_endianness, bool is64Bits>
778uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::count() {
779 return _sectionInfo.size();
780}
781template<support::endianness target_endianness, bool is64Bits>
782uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::size() {
783 return sizeof (Elf_Shdr);
784}
785
786template<support::endianness target_endianness, bool is64Bits>
787const char *ELFSectionHeaderChunk<target_endianness, is64Bits>::info() {
788 return "elf_section_header";
789}
790
791//===----------------------------------------------------------------------===//
792// ELFProgramHeaderChunk
793//===----------------------------------------------------------------------===//
794// TODO: Implement the methods
795
796//===----------------------------------------------------------------------===//
797// ELFWriter Class
798//===----------------------------------------------------------------------===//
799template<support::endianness target_endianness, bool is64Bits>
800class ELFWriter : public Writer {
801public:
802 LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
803 typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000804 typedef object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000805 ELFWriter(const WriterOptionsELF &options);
806 virtual error_code writeFile(const lld::File &File, StringRef path);
Sid Manningdd110202012-09-25 18:22:09 +0000807 uint64_t addressOfAtom(const Atom *atom);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000808 ArrayRef<Chunk<target_endianness, is64Bits>*> chunks() { return _chunks; }
Sid Manningdd110202012-09-25 18:22:09 +0000809 KindHandler *kindHandler() { return _referenceKindHandler.get(); }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000810
811 std::vector<SectionChunk<target_endianness, is64Bits>*> sectionChunks() {
812 return _sectionChunks ;
813 }
814
815 ELFStringSectionChunk<target_endianness, is64Bits> *shstrtab() {
816 return _shstrtable;
817 }
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000818
819 ELFStringSectionChunk<target_endianness, is64Bits> *strtab() {
820 return _strtable;
821 }
822 ELFSymbolTableChunk<target_endianness, is64Bits> *symtab() {
823 return _symtable;
824 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000825
826private:
827 void build(const lld::File &file);
828 void createChunks(const lld::File &file);
Sid Manningdd110202012-09-25 18:22:09 +0000829 void buildAtomToAddressMap();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000830 void assignFileOffsets();
831 const WriterOptionsELF &_options;
Sid Manningdd110202012-09-25 18:22:09 +0000832
833/// \brief AtomToAddress: Is a mapping from an Atom to the address where
834/// it will live in the output file.
835 typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
836
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000837 ELFStringSectionChunk<target_endianness, is64Bits> *_shstrtable ;
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000838 ELFStringSectionChunk<target_endianness, is64Bits> *_strtable ;
839 ELFSymbolTableChunk<target_endianness, is64Bits> *_symtable;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000840 std::unique_ptr<KindHandler> _referenceKindHandler;
841 ELFSectionHeaderChunk<target_endianness, is64Bits> *_sectionHeaderChunk;
Sid Manningdd110202012-09-25 18:22:09 +0000842 AtomToAddress _atomToAddress;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000843 std::vector<Chunk<target_endianness, is64Bits>*> _chunks;
844 const DefinedAtom *_entryAtom;
845 std::vector<SectionChunk<target_endianness, is64Bits>*> _sectionChunks;
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000846 std::vector<StockSectionChunk<target_endianness, is64Bits>*>
847 _stockSectionChunks;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000848 llvm::BumpPtrAllocator _chunkAllocate;
849};
850
851//===----------------------------------------------------------------------===//
852// ELFWriter
853//===----------------------------------------------------------------------===//
854template<support::endianness target_endianness, bool is64Bits>
855ELFWriter<target_endianness, is64Bits>
856 ::ELFWriter(const WriterOptionsELF &options)
857 : _options(options)
Sid Manning42064e52012-10-09 02:20:47 +0000858 , _referenceKindHandler(KindHandler::makeHandler(_options.machine(),
859 target_endianness))
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000860{}
861
862template<support::endianness target_endianness, bool is64Bits>
863void ELFWriter<target_endianness, is64Bits>::build(const lld::File &file){
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000864// Create objects for each chunk.
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000865 createChunks(file);
866 assignFileOffsets();
Sid Manningdd110202012-09-25 18:22:09 +0000867 buildAtomToAddressMap();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000868}
869
870template<support::endianness target_endianness, bool is64Bits>
871void ELFWriter<target_endianness, is64Bits>
872 ::createChunks (const lld::File &file) {
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000873 std::map<StringRef, StockSectionChunk<target_endianness, is64Bits>*>
874 sectionMap;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000875
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000876// Make header chunk
877 ELFHeaderChunk<target_endianness, is64Bits> *ehc =
878 new (_chunkAllocate.Allocate
879 <ELFHeaderChunk<target_endianness, is64Bits>>())
880 ELFHeaderChunk<target_endianness, is64Bits>(_options, file);
881 _chunks.push_back(ehc);
882
883 _sectionHeaderChunk = new (_chunkAllocate.Allocate<ELFSectionHeaderChunk
884 <target_endianness, is64Bits>>())
885 ELFSectionHeaderChunk
886 <target_endianness, is64Bits>(_options, *this);
887 _chunks.push_back(_sectionHeaderChunk);
888// We need to create hand crafted sections such as shstrtab strtab hash and
889// symtab to put relevant information in ELF structures and then process the
890// atoms.
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000891
892 _shstrtable = new (_chunkAllocate.Allocate
893 <ELFStringSectionChunk<target_endianness, is64Bits>>())
894 ELFStringSectionChunk<target_endianness, is64Bits>
895 (_options, *this, ".shstrtab");
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000896 _shstrtable->setShStrtableOffset(_shstrtable->addString(".shstrtab"));
897 _sectionChunks.push_back(_shstrtable);
898
899 _strtable = new (_chunkAllocate.Allocate
900 <ELFStringSectionChunk<target_endianness, is64Bits>>())
901 ELFStringSectionChunk<target_endianness, is64Bits>
902 (_options, *this, ".strtab");
903 _strtable->setShStrtableOffset( _shstrtable->addString(".strtab"));
904 _sectionChunks.push_back(_strtable);
905
906 _symtable = new (_chunkAllocate.Allocate
907 <ELFSymbolTableChunk<target_endianness, is64Bits>>())
908 ELFSymbolTableChunk<target_endianness, is64Bits>
909 (_options, *this, ".symtab");
910 _symtable->setShStrtableOffset( _shstrtable->addString(".symtab"));
911 _sectionChunks.push_back(_symtable);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000912
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000913//TODO: implement .hash section
914
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000915 for (const DefinedAtom *a : file.defined() ) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000916 StringRef sectionName = a->customSectionName();
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000917 if (a->sectionChoice() ==
918 DefinedAtom::SectionChoice::sectionBasedOnContent) {
Hemant Kulkarni8bd27612012-10-03 23:27:33 +0000919 if (a->contentType() == DefinedAtom::typeZeroFill)
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000920 sectionName = ".bss";
921 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000922 auto pos = sectionMap.find(sectionName);
923 DefinedAtom::ContentType type = a->contentType();
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000924 if (type != DefinedAtom::typeUnknown){
925 if (pos == sectionMap.end()) {
926 StockSectionChunk<target_endianness, is64Bits>
927 *chunk = new(_chunkAllocate.Allocate
928 <StockSectionChunk<target_endianness, is64Bits>>
929 ())StockSectionChunk<target_endianness, is64Bits>
930 (sectionName, true, type, _options, *this);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000931
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000932 sectionMap[sectionName] = chunk;
933 chunk->appendAtom(a);
934 _sectionChunks.push_back(chunk);
935 _stockSectionChunks.push_back(chunk);
936
937 } else {
938 pos->second->appendAtom(a);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000939 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000940 }
941 }
942
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000943 for (auto chnk : _sectionChunks)
944 _chunks.push_back(chnk);
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000945
946// After creating chunks, we might lay them out diffrently.
947// Lets make sure symbol table, string table and section string table
948// are at the end. In future we might provide knob
949// to the driver to decide layout.
950 swapChunkPositions(*_chunks[_chunks.size() - 1],
951 *reinterpret_cast<Chunk<target_endianness,
952 is64Bits>*>(_shstrtable));
953 swapChunkPositions(*_chunks[_chunks.size() - 2],
954 *reinterpret_cast<Chunk<target_endianness,
955 is64Bits>*>(_strtable));
956 swapChunkPositions(*_chunks[_chunks.size() - 3],
957 *reinterpret_cast<Chunk<target_endianness,
958 is64Bits>*>(_symtable));
959// We sort the _chunks vector to have all chunks as per ordianl number
960// this will help to write out the chunks in the order we decided
961
962 std::stable_sort(_chunks.begin(), _chunks.end(),([]
963 (const Chunk<target_endianness, is64Bits> *A,
964 const Chunk<target_endianness, is64Bits> *B) -> bool {
965 return (A->ordinal() < B->ordinal());}));
966
967 std::stable_sort(_sectionChunks.begin(), _sectionChunks.end(),([]
968 (const SectionChunk<target_endianness, is64Bits> *A,
969 const SectionChunk<target_endianness, is64Bits> *B) -> bool {
970 return (A->ordinal() < B->ordinal());}));
971
972// Once the layout is fixed, we can now go and populate symbol table
973// with correct st_shndx member.
974
975 for (auto chnk : _sectionChunks ){
976 Elf_Sym *sym = new (_chunkAllocate.Allocate<Elf_Sym>())Elf_Sym;
977 sym->st_name = 0;
978 sym->st_value = 0;
979 sym->st_size = 0;
980 sym->st_other = ELF::STV_DEFAULT;
981// first two chunks are not sections hence we subtract 2 but there is a
982// NULL section in section table so add 1
983 sym->st_shndx = chnk->ordinal() - 1 ;
984 sym->setBindingAndType(ELF::STB_LOCAL, ELF::STT_SECTION);
985 _symtable->addSymbol(sym);
986 }
987
988 for (const auto ssc : _stockSectionChunks){
989 for (const auto da : ssc->atoms()) {
990 _symtable->addSymbol(std::get<0>(da), ssc->ordinal() -1);
991 }
992 }
993 for (const UndefinedAtom *a : file.undefined()) {
994 _symtable->addSymbol(a, ELF::SHN_UNDEF);
995 }
996
997 for (const AbsoluteAtom *a : file.absolute()) {
998 _symtable->addSymbol(a, ELF::SHN_ABS);
999 }
1000
1001 _sectionHeaderChunk->createHeaders();
1002 ehc->e_shoff(ehc->size());
1003 ehc->e_shentsize(_sectionHeaderChunk->size());
1004 ehc->e_shnum(_sectionHeaderChunk->count());
1005// We need to put the index of section string table in ELF header
1006// first two chunks are not sections so we subtract 2 to start sections
1007// and add 1 since we have a NULL header
1008 ehc->e_shstrndx(_shstrtable->ordinal() - 1);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +00001009}
1010
Sid Manningdd110202012-09-25 18:22:09 +00001011template<support::endianness target_endianness, bool is64Bits>
1012void ELFWriter<target_endianness, is64Bits>
1013 ::buildAtomToAddressMap () {
1014
1015// _atomToAddress is a DenseMap that maps an atom its file address.
1016// std::get<1>(ai) is the offset from the start of the section to the atom.
Hemant Kulkarni08e410292012-10-01 23:53:20 +00001017 for (auto chunk : _stockSectionChunks){
Sid Manningdd110202012-09-25 18:22:09 +00001018 for (auto &ai : chunk->atoms() ) {
1019 _atomToAddress[std::get<0>(ai)] = chunk->address() + std::get<1>(ai);
1020 }
1021 }
Sid Manningdd110202012-09-25 18:22:09 +00001022}
Hemant Kulkarni927bbc22012-09-14 16:11:34 +00001023
1024template<support::endianness target_endianness, bool is64Bits>
1025void ELFWriter<target_endianness, is64Bits>::assignFileOffsets() {
1026 DEBUG_WITH_TYPE("WriterELF-layout", dbgs()
1027 << "assign file offsets:\n");
1028 uint64_t offset = 0;
1029 uint64_t address = 0;
1030 for (auto chunk : _chunks) {
1031
1032 chunk->assignFileOffset(offset, address);
1033 }
1034 //TODO: We need to fix all file offsets inside various ELF section headers
1035 std::vector<Elf_Shdr*> secInfo = _sectionHeaderChunk->sectionInfo();
1036 typename std::vector<Elf_Shdr*>::iterator it = secInfo.begin();
1037 // First section is a NULL section with no sh_offset fix
1038 (*it)->sh_offset = 0;
1039 (*it)->sh_addr = 0;
1040 ++it;
1041 for (auto &chunk : _sectionChunks){
1042 (*it)->sh_offset = chunk->fileOffset();
1043 (*it)->sh_addr = chunk->address();
1044 ++it;
1045 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +00001046}
1047
1048template<support::endianness target_endianness, bool is64Bits>
1049error_code ELFWriter<target_endianness, is64Bits>
1050 ::writeFile(const lld::File &file, StringRef path) {
1051 build(file);
1052
1053 uint64_t totalSize = _chunks.back()->fileOffset() + _chunks.back()->size();
1054
1055 OwningPtr<FileOutputBuffer> buffer;
1056 error_code ec = FileOutputBuffer::create(path,
1057 totalSize, buffer,
1058 FileOutputBuffer::F_executable);
1059 if (ec)
1060 return ec;
1061
1062 for (auto chunk : _chunks) {
1063 chunk->write(buffer->getBufferStart() + chunk->fileOffset());
1064 }
1065 return buffer->commit();
1066}
Nick Kledzikabb69812012-05-31 22:34:00 +00001067
Sid Manningdd110202012-09-25 18:22:09 +00001068template<support::endianness target_endianness, bool is64Bits>
1069uint64_t ELFWriter<target_endianness, is64Bits>
1070 ::addressOfAtom(const Atom *atom) {
1071 return _atomToAddress[atom];
1072}
Nick Kledzikabb69812012-05-31 22:34:00 +00001073} // namespace elf
1074
Hemant Kulkarni927bbc22012-09-14 16:11:34 +00001075Writer *createWriterELF(const WriterOptionsELF &options) {
1076 if (!options.is64Bit() && options.endianness() == llvm::support::little)
Hemant Kulkarni08e410292012-10-01 23:53:20 +00001077 return new lld::elf::ELFWriter<support::little, false>(options);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +00001078 else if (options.is64Bit() && options.endianness() == llvm::support::little)
1079 return new lld::elf::ELFWriter<support::little, true>(options);
1080 else if (!options.is64Bit() && options.endianness() == llvm::support::big)
1081 return new lld::elf::ELFWriter<support::big, false>(options);
1082 else if (options.is64Bit() && options.endianness() == llvm::support::big)
1083 return new lld::elf::ELFWriter<support::big, true>(options);
Nick Kledzikabb69812012-05-31 22:34:00 +00001084
Hemant Kulkarni927bbc22012-09-14 16:11:34 +00001085 llvm_unreachable("Invalid Options!");
Nick Kledzikabb69812012-05-31 22:34:00 +00001086}
Nick Kledzikabb69812012-05-31 22:34:00 +00001087} // namespace lld