blob: c81ddaae8f750ea145daec8d1545927ddf4f5fe1 [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;
400 case DefinedAtom::typeConstant:
401 this->_type = ELF::SHT_PROGBITS;
402 break;
403 default:
404 llvm_unreachable("Unhandled content type for section!");
405 }
406}
407
408
409template<support::endianness target_endianness, bool is64Bits>
410const ArrayRef<AtomInfo> StockSectionChunk<target_endianness, is64Bits>::
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000411 atoms() const {
412 return _atoms;
413}
414
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000415template<support::endianness target_endianness, bool is64Bits>
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000416void StockSectionChunk<target_endianness, is64Bits>::
417 appendAtom(const DefinedAtom *atom) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000418 // Figure out offset for atom in this section given alignment constraints.
419 uint64_t offset = this->_size;
420 DefinedAtom::Alignment atomAlign = atom->alignment();
421 uint64_t align2 = 1 << atomAlign.powerOf2;
422 uint64_t requiredModulus = atomAlign.modulus;
423 uint64_t currentModulus = (offset % align2);
424 if (currentModulus != requiredModulus) {
425 if (requiredModulus > currentModulus)
426 offset += requiredModulus - currentModulus;
427 else
428 offset += align2 + requiredModulus - currentModulus;
429 }
430 // Record max alignment of any atom in this section.
431 if (align2 > this->_align2)
432 this->_align2 = align2;
433 // Assign atom to this section with this offset.
434 _atoms.emplace_back(atom, offset);
435 // Update section size to include this atom.
436 this->_size = offset + atom->size();
437 // Update permissions
438 DefinedAtom::ContentPermissions perms = atom->permissions();
439
440 // TODO: Check content permissions and figure out what to do with .bss
441 if ((perms & DefinedAtom::permR__) == DefinedAtom::permR__)
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000442 this->_flags |= ELF::SHF_ALLOC;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000443 if ((perms & DefinedAtom::permRW_) == DefinedAtom::permRW_)
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000444 this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_WRITE);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000445 if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000446 this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000447}
448
449template<support::endianness target_endianness, bool is64Bits>
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000450void StockSectionChunk<target_endianness, is64Bits>
451 ::write(uint8_t *chunkBuffer) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000452 // Each section's content is just its atoms' content.
453 for (const auto &ai : _atoms ) {
454 // Copy raw content of atom to file buffer.
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000455 ArrayRef<uint8_t> content = std::get<0>(ai)->rawContent();
456 uint64_t contentSize = content.size();
457 if (contentSize == 0)
458 continue;
459 uint8_t *atomContent = chunkBuffer + std::get<1>(ai);
460 std::copy_n(content.data(), contentSize, atomContent);
Sid Manningdd110202012-09-25 18:22:09 +0000461
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000462 for (const Reference *ref : *std::get<0>(ai)){
463 uint32_t offset = ref->offsetInAtom();
464 uint64_t targetAddress = 0;
Sid Manningdd110202012-09-25 18:22:09 +0000465
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000466 if ( ref->target() != nullptr )
467 targetAddress = this->_writer.addressOfAtom(ref->target());
Sid Manningdd110202012-09-25 18:22:09 +0000468
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000469 uint64_t fixupAddress = this->_writer.addressOfAtom(std::get<0>(ai)) +
470 offset;
471 this->_writer.kindHandler()->applyFixup(ref->kind(), ref->addend(),
472 &atomContent[offset],
473 fixupAddress,
474 targetAddress);
Sid Manningdd110202012-09-25 18:22:09 +0000475 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000476 }
477}
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000478
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000479//===----------------------------------------------------------------------===//
480// ELFStringSectionChunk
481//===----------------------------------------------------------------------===//
482template<support::endianness target_endianness, bool is64Bits>
483ELFStringSectionChunk<target_endianness, is64Bits>::
484 ELFStringSectionChunk(const WriterOptionsELF &options,
485 ELFWriter<target_endianness, is64Bits> &writer,
486 StringRef secName)
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000487 : SectionChunk<target_endianness, is64Bits>(secName, "PT_NULL",
488 false, 0lu, 0lu, 0lu,
489 ELF::SHT_STRTAB, 0lu, options,
490 writer) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000491 // First Add a null character. It also occupies 1 byte
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000492 _stringSection.emplace_back("");
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000493 this->_size = 1;
494}
495
496template<support::endianness target_endianness, bool is64Bits>
497uint64_t ELFStringSectionChunk<target_endianness, is64Bits>::
498 addString(StringRef symName) {
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000499 _stringSection.emplace_back(symName);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000500 uint64_t offset = this->_size;
501 this->_size += symName.size() + 1;
502
503 return offset;
504}
505
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000506// We need to unwrap the _stringSection and then make one large memory
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000507// chunk of null terminated strings
508template<support::endianness target_endianness, bool is64Bits>
509void ELFStringSectionChunk<target_endianness, is64Bits>::
510 write(uint8_t *chunkBuffer) {
511 uint64_t chunkOffset = 0;
512
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000513 for (auto it : _stringSection) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000514 ::memcpy(chunkBuffer + chunkOffset, it.data(), it.size());
515 chunkOffset += it.size();
516 ::memcpy(chunkBuffer + chunkOffset, "", 1);
517 chunkOffset += 1;
518 }
519}
520
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000521template<support::endianness target_endianness, bool is64Bits>
522const char *ELFStringSectionChunk<target_endianness, is64Bits>::info() {
523 return "String Table";
524}
525
526//===----------------------------------------------------------------------===//
527// ELFSymbolTableChunk
528//===----------------------------------------------------------------------===//
529template< support::endianness target_endianness, bool is64Bits>
530ELFSymbolTableChunk<target_endianness, is64Bits>::ELFSymbolTableChunk
531 (const WriterOptionsELF &options,
532 ELFWriter<target_endianness, is64Bits> &writer,
533 StringRef secName)
534 : SectionChunk<target_endianness, is64Bits>(secName, StringRef("PT_NULL"),
535 false, 0, 0, 0, ELF::SHT_SYMTAB,
536 sizeof(Elf_Sym), options, writer)
537{
538 _stringSection = this->_writer.strtab();
539 Elf_Sym *symbol = new (_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
540 memset ((void *)symbol,0, sizeof(Elf_Sym));
541 _symbolTable.push_back(symbol);
542 this->_link = 0;
543 this->_entsize = sizeof(Elf_Sym);
544 this->_size = sizeof(Elf_Sym);
545}
546
547template< support::endianness target_endianness, bool is64Bits>
548void ELFSymbolTableChunk<target_endianness, is64Bits>::addSymbol(Elf_Sym *sym){
549 _symbolTable.push_back(sym);
550 this->_size+= sizeof(Elf_Sym) ;
551}
552
553/// \brief Add symbols to symbol table
554/// We examine each property of atom to infer the various st_* fields in Elf*_Sym
555template< support::endianness target_endianness, bool is64Bits>
556void ELFSymbolTableChunk<target_endianness, is64Bits>
557 ::addSymbol(const Atom *a, uint16_t shndx) {
558 Elf_Sym *symbol = new(_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
559 unsigned char b = 0, t = 0;
560
561 symbol->st_name = _stringSection->addString(a->name());
562// In relocatable files, st_value holds a section offset for a defined symbol.
563// st_value is an offset from the beginning of the section that st_shndx
564// identifies. After we assign file offsets we can set this value correctly.
565 symbol->st_size = 0;
566 symbol->st_shndx = shndx;
567 symbol->st_value = 0;
568// FIXME: Need to change and account all STV* when visibilities are supported
569 symbol->st_other = ELF::STV_DEFAULT;
570 if (const DefinedAtom *da = llvm::dyn_cast<const DefinedAtom>(a)){
571 symbol->st_size = da->size();
572 lld::DefinedAtom::ContentType ct;
573 switch (ct = da->contentType()){
574 case DefinedAtom::typeCode:
575 t = ELF::STT_FUNC;
576 break;
577 case DefinedAtom::typeData:
578 t = ELF::STT_OBJECT;
579 break;
580 case DefinedAtom::typeZeroFill:
581 // In relocatable files, st_value holds alignment constraints for a symbol whose
582 // section index is SHN_COMMON
583 if (this->_options.type() == ELF::ET_REL){
584 t = ELF::STT_COMMON;
585 symbol->st_value = 1 << (da->alignment()).powerOf2;
586 symbol->st_shndx = ELF::SHN_COMMON;
587 }
588 break;
589 case DefinedAtom::typeFirstInSection:
590 t = ELF::STT_SECTION;
591 break;
592 // TODO:: How to find STT_FILE symbols?
593 default:
594 t = ELF::STT_NOTYPE;
595 }
596
597 if (da->scope() == DefinedAtom::scopeTranslationUnit)
598 b = ELF::STB_LOCAL;
599 else if (da->merge() == DefinedAtom::mergeAsWeak)
600 b = ELF::STB_WEAK;
601 else
602 b = ELF::STB_GLOBAL;
603 } else if (const AbsoluteAtom *aa = llvm::dyn_cast<const AbsoluteAtom>(a)){
604//FIXME: Absolute atoms need more properties to differentiate each other
605// based on binding and type of symbol
606 symbol->st_value = aa->value();
607 } else {
608 symbol->st_value = 0;
609 t = ELF::STT_NOTYPE;
610 b = ELF::STB_LOCAL;
611 }
612 symbol->setBindingAndType(b, t);
613
614 _symbolTable.push_back(symbol);
615 this->_size += sizeof(Elf_Sym);
616}
617
618template<support::endianness target_endianness, bool is64Bits>
619void ELFSymbolTableChunk<target_endianness, is64Bits>::setAttributes() {
620// sh_info should be one greater than last symbol with STB_LOCAL binding
621// we sort the symbol table to keep all local symbols at the beginning
622 std::stable_sort(_symbolTable.begin(), _symbolTable.end(), ([]
623 (const Elf_Sym *A, const Elf_Sym *B) -> bool {
624 return (A->getBinding() < B->getBinding());}));
625 uint16_t shInfo = 0;
626 for (auto i : _symbolTable) {
627 if (i->getBinding() != ELF::STB_LOCAL)
628 break;
629 shInfo++;
630 }
631 this->_shinfo = shInfo;
632// we set the associated string table index in th sh_link member
633 this->_link = this->_writer.strtab()->ordinal() - 1;
634 this->_align2 = this->_options.pointerWidth();
635}
636
637template<support::endianness target_endianness, bool is64Bits>
638const char *ELFSymbolTableChunk<target_endianness, is64Bits>::info() {
639 return "Symbol Table";
640}
641
642template<support::endianness target_endianness, bool is64Bits>
643void ELFSymbolTableChunk<target_endianness, is64Bits>::
644 write(uint8_t *chunkBuffer) {
645 uint64_t chunkOffset = 0;
646 for (auto it : _symbolTable) {
647 ::memcpy(chunkBuffer + chunkOffset, it, this->_entsize);
648 chunkOffset += this->_entsize;
649 }
650}
651
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000652//===----------------------------------------------------------------------===//
653// ELFHeaderChunk
654//===----------------------------------------------------------------------===//
655template<support::endianness target_endianness, bool is64Bits>
656ELFHeaderChunk<target_endianness, is64Bits>
657 ::ELFHeaderChunk(const WriterOptionsELF &options,
658 const File &File) {
659 this->_size = size();
660 e_ident(ELF::EI_MAG0, 0x7f);
661 e_ident(ELF::EI_MAG1, 'E');
662 e_ident(ELF::EI_MAG2, 'L');
663 e_ident(ELF::EI_MAG3, 'F');
664 e_ident(ELF::EI_CLASS, (options.is64Bit() ? ELF::ELFCLASS64
665 : ELF::ELFCLASS32));
666 e_ident(ELF::EI_DATA, options.endianness());
667 e_ident(ELF::EI_VERSION, 1);
668 e_ident(ELF::EI_OSABI, ELF::ELFOSABI_NONE);
669
670 e_type(options.type());
671 e_machine(options.machine());
672 e_version(1);
673
674 e_entry(0ULL);
675 e_phoff(this->_size);
676 e_shoff(0ULL);
677
678 e_flags(0);
679 e_ehsize(this->_size);
680 e_phentsize(0);
681 e_phnum(0);
682 e_shentsize(0);
683 e_shnum(0);
684 e_shstrndx(0);
685}
686
687template<support::endianness target_endianness, bool is64Bits>
688StringRef ELFHeaderChunk<target_endianness, is64Bits>
689 ::segmentName() const {
690 return "ELF";
691}
692
693template<support::endianness target_endianness, bool is64Bits>
694void ELFHeaderChunk<target_endianness, is64Bits>
695 ::write(uint8_t *chunkBuffer) {
696 ::memcpy(chunkBuffer, &_eh, size());
697}
698
699template<support::endianness target_endianness, bool is64Bits>
700const char *ELFHeaderChunk<target_endianness, is64Bits>::info() {
701 return "elf_header";
702}
703
704//===----------------------------------------------------------------------===//
705// ELFSectionHeaderChunk
706// List of Section Headers:
707//[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
708//[ 0] NULL 00000000 000000 000000 00 0 0 0
709//[ 1] .text PROGBITS 00000000 000034 000040 00 AX 0 0 4
710//===----------------------------------------------------------------------===//
711template<support::endianness target_endianness, bool is64Bits>
712ELFSectionHeaderChunk<target_endianness, is64Bits>
713 ::ELFSectionHeaderChunk(const WriterOptionsELF& options,
714 ELFWriter<target_endianness,
715 is64Bits> &writer)
716 : _options(options)
717 , _writer(writer) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000718 this->_size = 0;
719 this->_align2 = 0;
720 // The first element in the list is always NULL
721 Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
722 ::memset(nullshdr, 0, sizeof (Elf_Shdr));
723 _sectionInfo.push_back(nullshdr);
724
725 this->_size += sizeof (Elf_Shdr);
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000726 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000727
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000728template<support::endianness target_endianness, bool is64Bits>
729void ELFSectionHeaderChunk<target_endianness, is64Bits>::createHeaders(){
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000730 ELFStringSectionChunk<target_endianness, is64Bits> *str = _writer.shstrtab();
731
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000732 for (const auto &chunk : _writer.sectionChunks()) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000733 Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
734 StringRef Name = chunk->sectionName();
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000735 if (chunk->shStrtableOffset() == 0){
736 chunk->setShStrtableOffset(str->addString(Name));
737 }
738 shdr->sh_name = chunk->shStrtableOffset();
739
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000740 shdr->sh_type = chunk->type();
741 shdr->sh_flags = chunk->flags();
742 // TODO: At the time of creation of this section header, we will not have
743 // any address and offset info. We revisit this after assigning the file
744 // offsets.
745 shdr->sh_offset = chunk->fileOffset();
746 shdr->sh_addr = chunk->address();
747 shdr->sh_size = chunk->size();
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000748 shdr->sh_link = chunk->link() ;
749 shdr->sh_info = chunk->shinfo();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000750 shdr->sh_addralign = chunk->align2();
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000751 shdr->sh_entsize = chunk->entsize();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000752
753 _sectionInfo.push_back(shdr);
754 this->_size += sizeof (Elf_Shdr);
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000755 _writer.symtab()->setAttributes();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000756 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000757}
758
759template<support::endianness target_endianness, bool is64Bits>
760StringRef ELFSectionHeaderChunk<target_endianness, is64Bits>
761 ::segmentName() const {
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000762 return "PT_NULL";
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000763}
764
765template<support::endianness target_endianness, bool is64Bits>
766void ELFSectionHeaderChunk<target_endianness, is64Bits>
767 ::write(uint8_t *chunkBuffer) {
768 for (const auto si : _sectionInfo) {
769 ::memcpy(chunkBuffer, si, sizeof(*si));
770 chunkBuffer += sizeof (*si);
771 }
772}
773
774template<support::endianness target_endianness, bool is64Bits>
775uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::count() {
776 return _sectionInfo.size();
777}
778template<support::endianness target_endianness, bool is64Bits>
779uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::size() {
780 return sizeof (Elf_Shdr);
781}
782
783template<support::endianness target_endianness, bool is64Bits>
784const char *ELFSectionHeaderChunk<target_endianness, is64Bits>::info() {
785 return "elf_section_header";
786}
787
788//===----------------------------------------------------------------------===//
789// ELFProgramHeaderChunk
790//===----------------------------------------------------------------------===//
791// TODO: Implement the methods
792
793//===----------------------------------------------------------------------===//
794// ELFWriter Class
795//===----------------------------------------------------------------------===//
796template<support::endianness target_endianness, bool is64Bits>
797class ELFWriter : public Writer {
798public:
799 LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
800 typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000801 typedef object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000802 ELFWriter(const WriterOptionsELF &options);
803 virtual error_code writeFile(const lld::File &File, StringRef path);
Sid Manningdd110202012-09-25 18:22:09 +0000804 uint64_t addressOfAtom(const Atom *atom);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000805 ArrayRef<Chunk<target_endianness, is64Bits>*> chunks() { return _chunks; }
Sid Manningdd110202012-09-25 18:22:09 +0000806 KindHandler *kindHandler() { return _referenceKindHandler.get(); }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000807
808 std::vector<SectionChunk<target_endianness, is64Bits>*> sectionChunks() {
809 return _sectionChunks ;
810 }
811
812 ELFStringSectionChunk<target_endianness, is64Bits> *shstrtab() {
813 return _shstrtable;
814 }
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000815
816 ELFStringSectionChunk<target_endianness, is64Bits> *strtab() {
817 return _strtable;
818 }
819 ELFSymbolTableChunk<target_endianness, is64Bits> *symtab() {
820 return _symtable;
821 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000822
823private:
824 void build(const lld::File &file);
825 void createChunks(const lld::File &file);
Sid Manningdd110202012-09-25 18:22:09 +0000826 void buildAtomToAddressMap();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000827 void assignFileOffsets();
828 const WriterOptionsELF &_options;
Sid Manningdd110202012-09-25 18:22:09 +0000829
830/// \brief AtomToAddress: Is a mapping from an Atom to the address where
831/// it will live in the output file.
832 typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
833
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000834 ELFStringSectionChunk<target_endianness, is64Bits> *_shstrtable ;
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000835 ELFStringSectionChunk<target_endianness, is64Bits> *_strtable ;
836 ELFSymbolTableChunk<target_endianness, is64Bits> *_symtable;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000837 std::unique_ptr<KindHandler> _referenceKindHandler;
838 ELFSectionHeaderChunk<target_endianness, is64Bits> *_sectionHeaderChunk;
Sid Manningdd110202012-09-25 18:22:09 +0000839 AtomToAddress _atomToAddress;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000840 std::vector<Chunk<target_endianness, is64Bits>*> _chunks;
841 const DefinedAtom *_entryAtom;
842 std::vector<SectionChunk<target_endianness, is64Bits>*> _sectionChunks;
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000843 std::vector<StockSectionChunk<target_endianness, is64Bits>*>
844 _stockSectionChunks;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000845 llvm::BumpPtrAllocator _chunkAllocate;
846};
847
848//===----------------------------------------------------------------------===//
849// ELFWriter
850//===----------------------------------------------------------------------===//
851template<support::endianness target_endianness, bool is64Bits>
852ELFWriter<target_endianness, is64Bits>
853 ::ELFWriter(const WriterOptionsELF &options)
854 : _options(options)
855 , _referenceKindHandler(KindHandler::makeHandler(_options.machine()))
856{}
857
858template<support::endianness target_endianness, bool is64Bits>
859void ELFWriter<target_endianness, is64Bits>::build(const lld::File &file){
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000860// Create objects for each chunk.
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000861 createChunks(file);
862 assignFileOffsets();
Sid Manningdd110202012-09-25 18:22:09 +0000863 buildAtomToAddressMap();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000864}
865
866template<support::endianness target_endianness, bool is64Bits>
867void ELFWriter<target_endianness, is64Bits>
868 ::createChunks (const lld::File &file) {
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000869 std::map<StringRef, StockSectionChunk<target_endianness, is64Bits>*>
870 sectionMap;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000871
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000872// Make header chunk
873 ELFHeaderChunk<target_endianness, is64Bits> *ehc =
874 new (_chunkAllocate.Allocate
875 <ELFHeaderChunk<target_endianness, is64Bits>>())
876 ELFHeaderChunk<target_endianness, is64Bits>(_options, file);
877 _chunks.push_back(ehc);
878
879 _sectionHeaderChunk = new (_chunkAllocate.Allocate<ELFSectionHeaderChunk
880 <target_endianness, is64Bits>>())
881 ELFSectionHeaderChunk
882 <target_endianness, is64Bits>(_options, *this);
883 _chunks.push_back(_sectionHeaderChunk);
884// We need to create hand crafted sections such as shstrtab strtab hash and
885// symtab to put relevant information in ELF structures and then process the
886// atoms.
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000887
888 _shstrtable = new (_chunkAllocate.Allocate
889 <ELFStringSectionChunk<target_endianness, is64Bits>>())
890 ELFStringSectionChunk<target_endianness, is64Bits>
891 (_options, *this, ".shstrtab");
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000892 _shstrtable->setShStrtableOffset(_shstrtable->addString(".shstrtab"));
893 _sectionChunks.push_back(_shstrtable);
894
895 _strtable = new (_chunkAllocate.Allocate
896 <ELFStringSectionChunk<target_endianness, is64Bits>>())
897 ELFStringSectionChunk<target_endianness, is64Bits>
898 (_options, *this, ".strtab");
899 _strtable->setShStrtableOffset( _shstrtable->addString(".strtab"));
900 _sectionChunks.push_back(_strtable);
901
902 _symtable = new (_chunkAllocate.Allocate
903 <ELFSymbolTableChunk<target_endianness, is64Bits>>())
904 ELFSymbolTableChunk<target_endianness, is64Bits>
905 (_options, *this, ".symtab");
906 _symtable->setShStrtableOffset( _shstrtable->addString(".symtab"));
907 _sectionChunks.push_back(_symtable);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000908
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000909//TODO: implement .hash section
910
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000911 for (const DefinedAtom *a : file.defined() ) {
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000912 StringRef sectionName = a->customSectionName();
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000913 if (a->sectionChoice() ==
914 DefinedAtom::SectionChoice::sectionBasedOnContent) {
915 if (a->size() <8)
916 sectionName = ".sbss";
917 else
918 sectionName = ".bss";
919 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000920 auto pos = sectionMap.find(sectionName);
921 DefinedAtom::ContentType type = a->contentType();
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000922 if (type != DefinedAtom::typeUnknown){
923 if (pos == sectionMap.end()) {
924 StockSectionChunk<target_endianness, is64Bits>
925 *chunk = new(_chunkAllocate.Allocate
926 <StockSectionChunk<target_endianness, is64Bits>>
927 ())StockSectionChunk<target_endianness, is64Bits>
928 (sectionName, true, type, _options, *this);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000929
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000930 sectionMap[sectionName] = chunk;
931 chunk->appendAtom(a);
932 _sectionChunks.push_back(chunk);
933 _stockSectionChunks.push_back(chunk);
934
935 } else {
936 pos->second->appendAtom(a);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000937 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000938 }
939 }
940
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000941 for (auto chnk : _sectionChunks)
942 _chunks.push_back(chnk);
Hemant Kulkarni08e410292012-10-01 23:53:20 +0000943
944// After creating chunks, we might lay them out diffrently.
945// Lets make sure symbol table, string table and section string table
946// are at the end. In future we might provide knob
947// to the driver to decide layout.
948 swapChunkPositions(*_chunks[_chunks.size() - 1],
949 *reinterpret_cast<Chunk<target_endianness,
950 is64Bits>*>(_shstrtable));
951 swapChunkPositions(*_chunks[_chunks.size() - 2],
952 *reinterpret_cast<Chunk<target_endianness,
953 is64Bits>*>(_strtable));
954 swapChunkPositions(*_chunks[_chunks.size() - 3],
955 *reinterpret_cast<Chunk<target_endianness,
956 is64Bits>*>(_symtable));
957// We sort the _chunks vector to have all chunks as per ordianl number
958// this will help to write out the chunks in the order we decided
959
960 std::stable_sort(_chunks.begin(), _chunks.end(),([]
961 (const Chunk<target_endianness, is64Bits> *A,
962 const Chunk<target_endianness, is64Bits> *B) -> bool {
963 return (A->ordinal() < B->ordinal());}));
964
965 std::stable_sort(_sectionChunks.begin(), _sectionChunks.end(),([]
966 (const SectionChunk<target_endianness, is64Bits> *A,
967 const SectionChunk<target_endianness, is64Bits> *B) -> bool {
968 return (A->ordinal() < B->ordinal());}));
969
970// Once the layout is fixed, we can now go and populate symbol table
971// with correct st_shndx member.
972
973 for (auto chnk : _sectionChunks ){
974 Elf_Sym *sym = new (_chunkAllocate.Allocate<Elf_Sym>())Elf_Sym;
975 sym->st_name = 0;
976 sym->st_value = 0;
977 sym->st_size = 0;
978 sym->st_other = ELF::STV_DEFAULT;
979// first two chunks are not sections hence we subtract 2 but there is a
980// NULL section in section table so add 1
981 sym->st_shndx = chnk->ordinal() - 1 ;
982 sym->setBindingAndType(ELF::STB_LOCAL, ELF::STT_SECTION);
983 _symtable->addSymbol(sym);
984 }
985
986 for (const auto ssc : _stockSectionChunks){
987 for (const auto da : ssc->atoms()) {
988 _symtable->addSymbol(std::get<0>(da), ssc->ordinal() -1);
989 }
990 }
991 for (const UndefinedAtom *a : file.undefined()) {
992 _symtable->addSymbol(a, ELF::SHN_UNDEF);
993 }
994
995 for (const AbsoluteAtom *a : file.absolute()) {
996 _symtable->addSymbol(a, ELF::SHN_ABS);
997 }
998
999 _sectionHeaderChunk->createHeaders();
1000 ehc->e_shoff(ehc->size());
1001 ehc->e_shentsize(_sectionHeaderChunk->size());
1002 ehc->e_shnum(_sectionHeaderChunk->count());
1003// We need to put the index of section string table in ELF header
1004// first two chunks are not sections so we subtract 2 to start sections
1005// and add 1 since we have a NULL header
1006 ehc->e_shstrndx(_shstrtable->ordinal() - 1);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +00001007}
1008
Sid Manningdd110202012-09-25 18:22:09 +00001009template<support::endianness target_endianness, bool is64Bits>
1010void ELFWriter<target_endianness, is64Bits>
1011 ::buildAtomToAddressMap () {
1012
1013// _atomToAddress is a DenseMap that maps an atom its file address.
1014// std::get<1>(ai) is the offset from the start of the section to the atom.
Hemant Kulkarni08e410292012-10-01 23:53:20 +00001015 for (auto chunk : _stockSectionChunks){
Sid Manningdd110202012-09-25 18:22:09 +00001016 for (auto &ai : chunk->atoms() ) {
1017 _atomToAddress[std::get<0>(ai)] = chunk->address() + std::get<1>(ai);
1018 }
1019 }
Sid Manningdd110202012-09-25 18:22:09 +00001020}
Hemant Kulkarni927bbc22012-09-14 16:11:34 +00001021
1022template<support::endianness target_endianness, bool is64Bits>
1023void ELFWriter<target_endianness, is64Bits>::assignFileOffsets() {
1024 DEBUG_WITH_TYPE("WriterELF-layout", dbgs()
1025 << "assign file offsets:\n");
1026 uint64_t offset = 0;
1027 uint64_t address = 0;
1028 for (auto chunk : _chunks) {
1029
1030 chunk->assignFileOffset(offset, address);
1031 }
1032 //TODO: We need to fix all file offsets inside various ELF section headers
1033 std::vector<Elf_Shdr*> secInfo = _sectionHeaderChunk->sectionInfo();
1034 typename std::vector<Elf_Shdr*>::iterator it = secInfo.begin();
1035 // First section is a NULL section with no sh_offset fix
1036 (*it)->sh_offset = 0;
1037 (*it)->sh_addr = 0;
1038 ++it;
1039 for (auto &chunk : _sectionChunks){
1040 (*it)->sh_offset = chunk->fileOffset();
1041 (*it)->sh_addr = chunk->address();
1042 ++it;
1043 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +00001044}
1045
1046template<support::endianness target_endianness, bool is64Bits>
1047error_code ELFWriter<target_endianness, is64Bits>
1048 ::writeFile(const lld::File &file, StringRef path) {
1049 build(file);
1050
1051 uint64_t totalSize = _chunks.back()->fileOffset() + _chunks.back()->size();
1052
1053 OwningPtr<FileOutputBuffer> buffer;
1054 error_code ec = FileOutputBuffer::create(path,
1055 totalSize, buffer,
1056 FileOutputBuffer::F_executable);
1057 if (ec)
1058 return ec;
1059
1060 for (auto chunk : _chunks) {
1061 chunk->write(buffer->getBufferStart() + chunk->fileOffset());
1062 }
1063 return buffer->commit();
1064}
Nick Kledzikabb69812012-05-31 22:34:00 +00001065
Sid Manningdd110202012-09-25 18:22:09 +00001066template<support::endianness target_endianness, bool is64Bits>
1067uint64_t ELFWriter<target_endianness, is64Bits>
1068 ::addressOfAtom(const Atom *atom) {
1069 return _atomToAddress[atom];
1070}
Nick Kledzikabb69812012-05-31 22:34:00 +00001071} // namespace elf
1072
Hemant Kulkarni927bbc22012-09-14 16:11:34 +00001073Writer *createWriterELF(const WriterOptionsELF &options) {
1074 if (!options.is64Bit() && options.endianness() == llvm::support::little)
Hemant Kulkarni08e410292012-10-01 23:53:20 +00001075 return new lld::elf::ELFWriter<support::little, false>(options);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +00001076 else if (options.is64Bit() && options.endianness() == llvm::support::little)
1077 return new lld::elf::ELFWriter<support::little, true>(options);
1078 else if (!options.is64Bit() && options.endianness() == llvm::support::big)
1079 return new lld::elf::ELFWriter<support::big, false>(options);
1080 else if (options.is64Bit() && options.endianness() == llvm::support::big)
1081 return new lld::elf::ELFWriter<support::big, true>(options);
Nick Kledzikabb69812012-05-31 22:34:00 +00001082
Hemant Kulkarni927bbc22012-09-14 16:11:34 +00001083 llvm_unreachable("Invalid Options!");
Nick Kledzikabb69812012-05-31 22:34:00 +00001084}
Nick Kledzikabb69812012-05-31 22:34:00 +00001085} // namespace lld