blob: e01efd11c88c39726c4c07a7ca8cbecf3f161acb [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);
66
67protected:
68 Chunk();
69
70 uint64_t _size;
71 uint64_t _address;
72 uint64_t _fileOffset;
73 uint64_t _align2;
74};
75
76/// Pair of atom and offset in section.
77typedef std::tuple<const DefinedAtom*, uint64_t> AtomInfo;
78
79/// \brief A Section represents a set of Atoms assigned to a specific ELF
80/// Section.
81template<support::endianness target_endianness, bool is64Bits>
82class SectionChunk : public Chunk<target_endianness, is64Bits> {
83public:
84 SectionChunk(DefinedAtom::ContentType,
85 StringRef sectionName,
86 const WriterOptionsELF &options,
87 ELFWriter<target_endianness, is64Bits> &writer);
88
89 virtual StringRef segmentName() const;
90 virtual bool occupiesNoDiskSpace();
91 virtual void write(uint8_t *fileBuffer);
92 virtual const char *info();
93 StringRef sectionName();
94 uint32_t flags() const;
95 uint32_t type() const;
96 uint32_t permissions();
97 void appendAtom(const DefinedAtom*);
98 const ArrayRef<AtomInfo> atoms() const;
99
100private:
101 StringRef _segmentName;
102 StringRef _sectionName;
103 const WriterOptionsELF &_options;
104 ELFWriter<target_endianness, is64Bits> &_writer;
105 uint32_t _flags;
106 uint32_t _type;
107 uint32_t _permissions;
108 std::vector<AtomInfo> _atoms;
109};
110
111/// \brief An ELFHeaderChunk represents the Elf[32/64]_Ehdr structure at the
112/// start of an ELF executable file.
113template<support::endianness target_endianness, bool is64Bits>
114class ELFHeaderChunk : public Chunk<target_endianness, is64Bits> {
115public:
116 LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
117 typedef object::Elf_Ehdr_Impl<target_endianness, is64Bits> Elf_Ehdr;
118
119 ELFHeaderChunk(const WriterOptionsELF &options,
120 const File &file);
121
122 void e_ident(int I, unsigned char C) { _eh.e_ident[I] = C; }
123 void e_type(uint16_t type) { _eh.e_type = type; }
124 void e_machine(uint16_t machine) { _eh.e_machine = machine; }
125 void e_version(uint32_t version) { _eh.e_version = version; }
126 void e_entry(uint64_t entry) { _eh.e_entry = entry; }
127 void e_phoff(uint64_t phoff) { _eh.e_phoff = phoff; }
128 void e_shoff(uint64_t shoff) { _eh.e_shoff = shoff; }
129 void e_flags(uint32_t flags) { _eh.e_flags = flags; }
130 void e_ehsize(uint16_t ehsize) { _eh.e_ehsize = ehsize; }
131 void e_phentsize(uint16_t phentsize) { _eh.e_phentsize = phentsize; }
132 void e_phnum(uint16_t phnum) { _eh.e_phnum = phnum; }
133 void e_shentsize(uint16_t shentsize) { _eh.e_shentsize = shentsize; }
134 void e_shnum(uint16_t shnum) { _eh.e_shnum = shnum; }
135 void e_shstrndx(uint16_t shstrndx) { _eh.e_shstrndx = shstrndx; }
136
137 uint64_t size() { return sizeof (Elf_Ehdr); }
138
139 virtual StringRef segmentName() const;
140 virtual void write(uint8_t *fileBuffer);
141 virtual const char *info();
142
143private:
144 Elf_Ehdr _eh;
145};
146
147
148/// \brief An ELFSectionHeaderChunk represents the Elf[32/64]_Shdr structure
149/// that is placed right after the ELFHeader.
150///
151/// When this is finished it will need to update the header with the size and
152/// number of section headers, e_shentsize, e_shnum.
153template<support::endianness target_endianness, bool is64Bits>
154class ELFSectionHeaderChunk : public Chunk<target_endianness, is64Bits> {
155public:
156 LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
157 typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
158 ELFSectionHeaderChunk(const WriterOptionsELF &Options,
159 ELFWriter<target_endianness, is64Bits>&);
160
161 virtual StringRef segmentName() const;
162 virtual void write(uint8_t *filebuffer);
163 virtual const char *info();
164 void computeSize(const lld::File &file);
165 uint16_t count();
166 uint16_t size();
167
168 const ArrayRef<Elf_Shdr*> sectionInfo() {
169 return _sectionInfo;
170 }
171
172 bool is64Bit() { return _options.is64Bit(); }
173
174private:
175 const WriterOptionsELF &_options;
176 ELFWriter<target_endianness, is64Bits> &_writer;
177 llvm::BumpPtrAllocator _sectionAllocate;
178 std::vector<Elf_Shdr*> _sectionInfo;
179};
180
181/// \brief Represents the shstr section.
182///
183/// This is a contiguous memory that has all the symbol strings each ending with
184/// null character. We might need more than one such chunks shstrtab for setting
185/// e_shstrndx in ELHHeaderChunk and strtab for use with symtab
186template<support::endianness target_endianness, bool is64Bits>
187class ELFStringSectionChunk : public Chunk<target_endianness, is64Bits> {
188public:
189 LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
190 ELFStringSectionChunk(const WriterOptionsELF &Options,
191 ELFWriter<target_endianness, is64Bits> &writer,
192 StringRef secName);
193
194 uint64_t addString(StringRef symName);
195
196 virtual StringRef segmentName() const;
197 virtual void write(uint8_t *filebuffer);
198 virtual const char *info();
199 StringRef sectionName();
200
201
202
203private:
204 StringRef _segName;
205 std::vector<StringRef> _StringSection;
206 StringRef _sectionName;
207 ELFWriter<target_endianness, is64Bits> &_writer;
208 const WriterOptionsELF &_options;
209
210};
211
212
213/// An ELFProgramHeaderChunk represents the Elf[32/64]_Phdr structure near
214/// the start of an ELF executable file. Will need to update ELFHeader's
215/// e_phentsize/e_phnum when done.
216template<support::endianness target_endianness, bool is64Bits>
217class ELFProgramHeaderChunk : public Chunk<target_endianness, is64Bits> {
218public:
219 LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
220 ELFProgramHeaderChunk(ELFHeaderChunk<target_endianness, is64Bits>&,
221 const WriterOptionsELF &options,
222 const File &file);
223
224
225 virtual StringRef segmentName() const;
226 virtual void write(uint8_t *filebuffer);
227 virtual const char *info();
228
229private:
230// TODO: Replace this with correct ELF::* type method
231//uint32_t filetype(WriterOptionsELF::OutputKind kind);
232};
233
234
235//===----------------------------------------------------------------------===//
236// Chunk
237//===----------------------------------------------------------------------===//
238
239template<support::endianness target_endianness, bool is64Bits>
240Chunk<target_endianness, is64Bits>::Chunk()
241 : _size(0), _address(0), _fileOffset(0), _align2(0) {
242}
243
244template<support::endianness target_endianness, bool is64Bits>
245bool Chunk<target_endianness, is64Bits>::occupiesNoDiskSpace() {
246 return false;
247}
248
249template<support::endianness target_endianness, bool is64Bits>
250uint64_t Chunk<target_endianness, is64Bits>::size() const {
251 return _size;
252}
253
254template<support::endianness target_endianness, bool is64Bits>
255uint64_t Chunk<target_endianness, is64Bits>::align2() const {
256 return _align2;
257}
258
259template<support::endianness target_endianness, bool is64Bits>
260uint64_t Chunk<target_endianness, is64Bits>::address() const {
261 return _address;
262}
263
264template<support::endianness target_endianness, bool is64Bits>
265uint64_t Chunk<target_endianness, is64Bits>::fileOffset() const {
266 return _fileOffset;
267}
268
269template<support::endianness target_endianness, bool is64Bits>
270uint64_t Chunk<target_endianness, is64Bits>::
271 alignTo(uint64_t value, uint8_t align2) {
272 uint64_t align = 1 << align2;
273 return (value + (align - 1)) & (-align);
274}
275
276template<support::endianness target_endianness, bool is64Bits>
277void Chunk<target_endianness, is64Bits>::
278 assignFileOffset(uint64_t &curOffset, uint64_t &curAddress) {
279 if (occupiesNoDiskSpace()) {
280 // FileOffset does not change, but virtual address does change.
281 uint64_t alignedAddress =
282 alignTo(curAddress, _align2 ? static_cast<uint8_t>(llvm::Log2_64(_align2))
283 : 0);
284 _address = alignedAddress;
285 curAddress = alignedAddress + _size;
286 } else {
287 // FileOffset and address both move by _size amount after alignment.
288 uint64_t alignPadding =
289 alignTo(curAddress, _align2 ? static_cast<uint8_t>(llvm::Log2_64(_align2))
290 : 0) - curAddress;
291 _fileOffset = curOffset + alignPadding;
292 _address = curAddress + alignPadding;
293 curOffset = _fileOffset + _size;
294 curAddress = _address + _size;
295 }
296
297 DEBUG_WITH_TYPE("WriterELF-layout", dbgs()
298 << " fileOffset="
299 << format("0x%08X", _fileOffset)
300 << " address="
301 << format("0x%016X", _address)
302 << " info=" << info() << "\n");
303}
304
305//===----------------------------------------------------------------------===//
306// SectionChunk
307//===----------------------------------------------------------------------===//
308
309template<support::endianness target_endianness, bool is64Bits>
310SectionChunk<target_endianness, is64Bits>::
311 SectionChunk(DefinedAtom::ContentType type,
312 StringRef sectionName,
313 const WriterOptionsELF &options,
314 ELFWriter<target_endianness, is64Bits> &writer)
315 : _options(options)
316 , _writer(writer) {
317 switch(type) {
318 case DefinedAtom::typeCode:
319 _segmentName = "PT_LOAD";
320 _sectionName = sectionName;
321 _flags = ELF::SHF_ALLOC | ELF::SHF_EXECINSTR;
322 _type = ELF::SHT_PROGBITS;
323 break;
324 case DefinedAtom::typeData:
325 _segmentName = "PT_LOAD";
326 _sectionName = sectionName;
327 _flags = ELF::SHF_ALLOC | ELF::SHF_WRITE;
328 _type = ELF::SHT_PROGBITS;
329 break;
330 case DefinedAtom::typeZeroFill:
331 _segmentName = "PT_LOAD";
332 _sectionName = ".bss";
333 _flags = ELF::SHF_ALLOC | ELF::SHF_WRITE;
334 _type = ELF::SHT_NOBITS;
335 break;
336 default:
337 llvm_unreachable("Unhandled content type for section!");
338 }
339}
340
341template<support::endianness target_endianness, bool is64Bits>
342bool SectionChunk<target_endianness, is64Bits>::occupiesNoDiskSpace() {
343 return false;
344}
345
346template<support::endianness target_endianness, bool is64Bits>
347StringRef SectionChunk<target_endianness, is64Bits>::segmentName() const {
348 return _segmentName;
349}
350
351template<support::endianness target_endianness, bool is64Bits>
352StringRef SectionChunk<target_endianness, is64Bits>::sectionName() {
353 return _sectionName;
354}
355
356template<support::endianness target_endianness, bool is64Bits>
357uint32_t SectionChunk<target_endianness, is64Bits>::flags() const {
358 return _flags;
359}
360
361template<support::endianness target_endianness, bool is64Bits>
362uint32_t SectionChunk<target_endianness, is64Bits>::type() const {
363 return _type;
364}
365
366template<support::endianness target_endianness, bool is64Bits>
367uint32_t SectionChunk<target_endianness, is64Bits>::permissions() {
368 return _permissions;
369}
370
371template<support::endianness target_endianness, bool is64Bits>
372const char *SectionChunk<target_endianness, is64Bits>::info() {
373 return _sectionName.data();
374}
375
376template<support::endianness target_endianness, bool is64Bits>
377const ArrayRef<AtomInfo> SectionChunk<target_endianness, is64Bits>::
378 atoms() const {
379 return _atoms;
380}
381
382
383template<support::endianness target_endianness, bool is64Bits>
384void SectionChunk<target_endianness, is64Bits>::
385 appendAtom(const DefinedAtom *atom) {
386 // Figure out offset for atom in this section given alignment constraints.
387 uint64_t offset = this->_size;
388 DefinedAtom::Alignment atomAlign = atom->alignment();
389 uint64_t align2 = 1 << atomAlign.powerOf2;
390 uint64_t requiredModulus = atomAlign.modulus;
391 uint64_t currentModulus = (offset % align2);
392 if (currentModulus != requiredModulus) {
393 if (requiredModulus > currentModulus)
394 offset += requiredModulus - currentModulus;
395 else
396 offset += align2 + requiredModulus - currentModulus;
397 }
398 // Record max alignment of any atom in this section.
399 if (align2 > this->_align2)
400 this->_align2 = align2;
401 // Assign atom to this section with this offset.
402 _atoms.emplace_back(atom, offset);
403 // Update section size to include this atom.
404 this->_size = offset + atom->size();
405 // Update permissions
406 DefinedAtom::ContentPermissions perms = atom->permissions();
407
408 // TODO: Check content permissions and figure out what to do with .bss
409 if ((perms & DefinedAtom::permR__) == DefinedAtom::permR__)
410 this->_permissions |= ELF::SHF_ALLOC;
411 if ((perms & DefinedAtom::permRW_) == DefinedAtom::permRW_)
412 this->_permissions |= (ELF::SHF_ALLOC | ELF::SHF_WRITE);
413 if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
414 this->_permissions |= (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
415}
416
417template<support::endianness target_endianness, bool is64Bits>
418void SectionChunk<target_endianness, is64Bits>::write(uint8_t *chunkBuffer) {
419 // Each section's content is just its atoms' content.
420 for (const auto &ai : _atoms ) {
421 // Copy raw content of atom to file buffer.
422 ArrayRef<uint8_t> content = std::get<0>(ai)->rawContent();
423 uint64_t contentSize = content.size();
424 if (contentSize == 0)
425 continue;
426 uint8_t *atomContent = chunkBuffer + std::get<1>(ai);
427 std::copy_n(content.data(), contentSize, atomContent);
Sid Manningdd110202012-09-25 18:22:09 +0000428
429 for (const Reference *ref : *std::get<0>(ai)){
430 uint32_t offset = ref->offsetInAtom();
431 uint64_t targetAddress = 0;
432
433 if ( ref->target() != nullptr )
434 targetAddress = _writer.addressOfAtom(ref->target());
435
436 uint64_t fixupAddress = _writer.addressOfAtom(std::get<0>(ai)) + offset;
437 _writer.kindHandler()->applyFixup(ref->kind(), ref->addend(),
438 &atomContent[offset],
439 fixupAddress,
440 targetAddress);
441 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000442 }
443}
444//
445//===----------------------------------------------------------------------===//
446// ELFStringSectionChunk
447//===----------------------------------------------------------------------===//
448template<support::endianness target_endianness, bool is64Bits>
449ELFStringSectionChunk<target_endianness, is64Bits>::
450 ELFStringSectionChunk(const WriterOptionsELF &options,
451 ELFWriter<target_endianness, is64Bits> &writer,
452 StringRef secName)
453 : _segName("PT_NULL")
454 , _sectionName(secName)
455 , _writer(writer)
456 , _options(options) {
457 // First Add a null character. It also occupies 1 byte
458 _StringSection.emplace_back("");
459 this->_size = 1;
460}
461
462template<support::endianness target_endianness, bool is64Bits>
463uint64_t ELFStringSectionChunk<target_endianness, is64Bits>::
464 addString(StringRef symName) {
465 _StringSection.emplace_back(symName);
466
467 uint64_t offset = this->_size;
468 this->_size += symName.size() + 1;
469
470 return offset;
471}
472
473template<support::endianness target_endianness, bool is64Bits>
474const char *ELFStringSectionChunk<target_endianness, is64Bits>::info() {
475 return _sectionName.data();
476}
477
478template<support::endianness target_endianness, bool is64Bits>
479StringRef ELFStringSectionChunk<target_endianness, is64Bits>::sectionName() {
480 return _sectionName ;
481}
482
483template<support::endianness target_endianness, bool is64Bits>
484StringRef ELFStringSectionChunk<target_endianness, is64Bits>::
485 segmentName() const {
486 return _segName;
487}
488
489// We need to unwrap the _StringSection and then make one large memory
490// chunk of null terminated strings
491template<support::endianness target_endianness, bool is64Bits>
492void ELFStringSectionChunk<target_endianness, is64Bits>::
493 write(uint8_t *chunkBuffer) {
494 uint64_t chunkOffset = 0;
495
496 for (auto it : _StringSection) {
497 ::memcpy(chunkBuffer + chunkOffset, it.data(), it.size());
498 chunkOffset += it.size();
499 ::memcpy(chunkBuffer + chunkOffset, "", 1);
500 chunkOffset += 1;
501 }
502}
503
504//===----------------------------------------------------------------------===//
505// ELFHeaderChunk
506//===----------------------------------------------------------------------===//
507template<support::endianness target_endianness, bool is64Bits>
508ELFHeaderChunk<target_endianness, is64Bits>
509 ::ELFHeaderChunk(const WriterOptionsELF &options,
510 const File &File) {
511 this->_size = size();
512 e_ident(ELF::EI_MAG0, 0x7f);
513 e_ident(ELF::EI_MAG1, 'E');
514 e_ident(ELF::EI_MAG2, 'L');
515 e_ident(ELF::EI_MAG3, 'F');
516 e_ident(ELF::EI_CLASS, (options.is64Bit() ? ELF::ELFCLASS64
517 : ELF::ELFCLASS32));
518 e_ident(ELF::EI_DATA, options.endianness());
519 e_ident(ELF::EI_VERSION, 1);
520 e_ident(ELF::EI_OSABI, ELF::ELFOSABI_NONE);
521
522 e_type(options.type());
523 e_machine(options.machine());
524 e_version(1);
525
526 e_entry(0ULL);
527 e_phoff(this->_size);
528 e_shoff(0ULL);
529
530 e_flags(0);
531 e_ehsize(this->_size);
532 e_phentsize(0);
533 e_phnum(0);
534 e_shentsize(0);
535 e_shnum(0);
536 e_shstrndx(0);
537}
538
539template<support::endianness target_endianness, bool is64Bits>
540StringRef ELFHeaderChunk<target_endianness, is64Bits>
541 ::segmentName() const {
542 return "ELF";
543}
544
545template<support::endianness target_endianness, bool is64Bits>
546void ELFHeaderChunk<target_endianness, is64Bits>
547 ::write(uint8_t *chunkBuffer) {
548 ::memcpy(chunkBuffer, &_eh, size());
549}
550
551template<support::endianness target_endianness, bool is64Bits>
552const char *ELFHeaderChunk<target_endianness, is64Bits>::info() {
553 return "elf_header";
554}
555
556//===----------------------------------------------------------------------===//
557// ELFSectionHeaderChunk
558// List of Section Headers:
559//[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
560//[ 0] NULL 00000000 000000 000000 00 0 0 0
561//[ 1] .text PROGBITS 00000000 000034 000040 00 AX 0 0 4
562//===----------------------------------------------------------------------===//
563template<support::endianness target_endianness, bool is64Bits>
564ELFSectionHeaderChunk<target_endianness, is64Bits>
565 ::ELFSectionHeaderChunk(const WriterOptionsELF& options,
566 ELFWriter<target_endianness,
567 is64Bits> &writer)
568 : _options(options)
569 , _writer(writer) {
570
571 this->_size = 0;
572 this->_align2 = 0;
573 // The first element in the list is always NULL
574 Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
575 ::memset(nullshdr, 0, sizeof (Elf_Shdr));
576 _sectionInfo.push_back(nullshdr);
577
578 this->_size += sizeof (Elf_Shdr);
579
580 ELFStringSectionChunk<target_endianness, is64Bits> *str = _writer.shstrtab();
581
582 for (const auto &chunk : _writer.sectionChunks()) {
583 Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
584 StringRef Name = chunk->sectionName();
585 uint64_t offset = str->addString(Name);
586 shdr->sh_name = offset;
587 shdr->sh_type = chunk->type();
588 shdr->sh_flags = chunk->flags();
589 // TODO: At the time of creation of this section header, we will not have
590 // any address and offset info. We revisit this after assigning the file
591 // offsets.
592 shdr->sh_offset = chunk->fileOffset();
593 shdr->sh_addr = chunk->address();
594 shdr->sh_size = chunk->size();
595// The next two fields have special meanings:
596// sh_type sh_link sh_info
597// SHT_DYNAMIC The section header index of the string
598// table used by entries in the section. 0
599// SHT_HASH The section header index of the symbol
600// table to which the hash table applies. 0
601// SHT_REL
602// SHT_RELA The section header index of the
603// associated symbol table. The section header
604// index of the section
605// to which the
606// relocation applies.
607// SHT_SYMTAB
608// SHT_DYNSYM The section header index of the
609// associated string table. One greater than the
610// symbol table index of
611// the last local symbol
612// (binding STB_LOCAL).
613// SHT_GROUP The section header index of the
614// associated symbol table. The symbol table
615// index of an entry in
616// the associated symbol
617// table. The name of
618// the specified symbol
619// table entry provides
620// a signature for the
621// section group.
622// SHT_SYMTAB_SHNDX The section header index of
623// the associated symbol table section. 0
624// None of these chunks are of the above mentioned type, so we short them.
625 shdr->sh_link = 0;
626 shdr->sh_info = 0;
627 shdr->sh_addralign = chunk->align2();
628 // Not a special section with fixed entries
629 shdr->sh_entsize = 0;
630
631 _sectionInfo.push_back(shdr);
632 this->_size += sizeof (Elf_Shdr);
633 }
634
635 // Now I add in the section string table. For some reason This seems to be
636 // preferred location of string sections in contemporary
637 // (ones that must not be named) linker(s).
638 Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
639 // I push the name of the string table into the string table as soon as
640 // it is created.
641 shdr->sh_name = 1;
642 shdr->sh_type = ELF::SHT_STRTAB;
643 shdr->sh_flags = 0;
644 // NOTE: Refer to above note when assigning st_addr for other sections.
645 shdr->sh_addr = str->address();
646 shdr->sh_offset = str->fileOffset();
647 shdr->sh_size = str->size();
648 shdr->sh_link = 0;
649 shdr->sh_info = 0;
650 // This section is not a loadable section, hence we do not care about
651 // alignment.
652 shdr->sh_addralign = 1;
653 _sectionInfo.push_back(shdr);
654 this->_size += sizeof (Elf_Shdr);
655}
656
657template<support::endianness target_endianness, bool is64Bits>
658StringRef ELFSectionHeaderChunk<target_endianness, is64Bits>
659 ::segmentName() const {
660 return "SHDR";
661}
662
663template<support::endianness target_endianness, bool is64Bits>
664void ELFSectionHeaderChunk<target_endianness, is64Bits>
665 ::write(uint8_t *chunkBuffer) {
666 for (const auto si : _sectionInfo) {
667 ::memcpy(chunkBuffer, si, sizeof(*si));
668 chunkBuffer += sizeof (*si);
669 }
670}
671
672template<support::endianness target_endianness, bool is64Bits>
673uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::count() {
674 return _sectionInfo.size();
675}
676template<support::endianness target_endianness, bool is64Bits>
677uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::size() {
678 return sizeof (Elf_Shdr);
679}
680
681template<support::endianness target_endianness, bool is64Bits>
682const char *ELFSectionHeaderChunk<target_endianness, is64Bits>::info() {
683 return "elf_section_header";
684}
685
686//===----------------------------------------------------------------------===//
687// ELFProgramHeaderChunk
688//===----------------------------------------------------------------------===//
689// TODO: Implement the methods
690
691//===----------------------------------------------------------------------===//
692// ELFWriter Class
693//===----------------------------------------------------------------------===//
694template<support::endianness target_endianness, bool is64Bits>
695class ELFWriter : public Writer {
696public:
697 LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
698 typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
699 ELFWriter(const WriterOptionsELF &options);
700 virtual error_code writeFile(const lld::File &File, StringRef path);
Sid Manningdd110202012-09-25 18:22:09 +0000701 uint64_t addressOfAtom(const Atom *atom);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000702 ArrayRef<Chunk<target_endianness, is64Bits>*> chunks() { return _chunks; }
Sid Manningdd110202012-09-25 18:22:09 +0000703 KindHandler *kindHandler() { return _referenceKindHandler.get(); }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000704
705 std::vector<SectionChunk<target_endianness, is64Bits>*> sectionChunks() {
706 return _sectionChunks ;
707 }
708
709 ELFStringSectionChunk<target_endianness, is64Bits> *shstrtab() {
710 return _shstrtable;
711 }
712
713private:
714 void build(const lld::File &file);
715 void createChunks(const lld::File &file);
Sid Manningdd110202012-09-25 18:22:09 +0000716 void buildAtomToAddressMap();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000717 void assignFileOffsets();
718 const WriterOptionsELF &_options;
Sid Manningdd110202012-09-25 18:22:09 +0000719
720/// \brief AtomToAddress: Is a mapping from an Atom to the address where
721/// it will live in the output file.
722 typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
723
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000724 ELFStringSectionChunk<target_endianness, is64Bits> *_shstrtable ;
725 std::unique_ptr<KindHandler> _referenceKindHandler;
726 ELFSectionHeaderChunk<target_endianness, is64Bits> *_sectionHeaderChunk;
Sid Manningdd110202012-09-25 18:22:09 +0000727 AtomToAddress _atomToAddress;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000728 std::vector<Chunk<target_endianness, is64Bits>*> _chunks;
729 const DefinedAtom *_entryAtom;
730 std::vector<SectionChunk<target_endianness, is64Bits>*> _sectionChunks;
731 llvm::BumpPtrAllocator _chunkAllocate;
732};
733
734//===----------------------------------------------------------------------===//
735// ELFWriter
736//===----------------------------------------------------------------------===//
737template<support::endianness target_endianness, bool is64Bits>
738ELFWriter<target_endianness, is64Bits>
739 ::ELFWriter(const WriterOptionsELF &options)
740 : _options(options)
741 , _referenceKindHandler(KindHandler::makeHandler(_options.machine()))
742{}
743
744template<support::endianness target_endianness, bool is64Bits>
745void ELFWriter<target_endianness, is64Bits>::build(const lld::File &file){
746 // Create objects for each chunk.
747 createChunks(file);
748 assignFileOffsets();
Sid Manningdd110202012-09-25 18:22:09 +0000749 buildAtomToAddressMap();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000750}
751
752template<support::endianness target_endianness, bool is64Bits>
753void ELFWriter<target_endianness, is64Bits>
754 ::createChunks (const lld::File &file) {
755 std::map<StringRef, SectionChunk<target_endianness, is64Bits>*> sectionMap;
756
757 // We need to create hand crafted sections such as shstrtab strtab hash and
758 // symtab to put relevant information in ELF structures and then process the
759 // atoms.
760
761 _shstrtable = new (_chunkAllocate.Allocate
762 <ELFStringSectionChunk<target_endianness, is64Bits>>())
763 ELFStringSectionChunk<target_endianness, is64Bits>
764 (_options, *this, ".shstrtab");
765 _shstrtable->addString(".shstrtab");
766
767 //we also need to process undefined atoms
768 for (const DefinedAtom *a : file.defined() ) {
769 // TODO: Add sectionChoice.
770 // assert( atom->sectionChoice() == DefinedAtom::sectionBasedOnContent );
771 StringRef sectionName = a->customSectionName();
772 auto pos = sectionMap.find(sectionName);
773 DefinedAtom::ContentType type = a->contentType();
774 if (pos == sectionMap.end()) {
775 if (type != DefinedAtom::typeUnknown){
776 SectionChunk<target_endianness, is64Bits>
777 *chunk = new (_chunkAllocate.Allocate
778 <SectionChunk<target_endianness, is64Bits>>())
779 SectionChunk<target_endianness, is64Bits>
780 (type, sectionName, _options, *this);
781
782 sectionMap[sectionName] = chunk;
783 chunk->appendAtom(a);
784 _sectionChunks.push_back(chunk);
785 }
786 } else {
787 pos->second->appendAtom(a);
788 }
789 }
790
791 //put in the Undefined atoms as well
792 // Make header chunk
793 ELFHeaderChunk<target_endianness, is64Bits> *ehc =
794 new (_chunkAllocate.Allocate
795 <ELFHeaderChunk<target_endianness, is64Bits>>())
796 ELFHeaderChunk<target_endianness, is64Bits>(_options, file);
797
798 _sectionHeaderChunk = new (_chunkAllocate.Allocate<ELFSectionHeaderChunk
799 <target_endianness, is64Bits>>())
800 ELFSectionHeaderChunk
801 <target_endianness, is64Bits>(_options, *this);
802
803 ehc->e_shoff(ehc->size());
804 ehc->e_shentsize(_sectionHeaderChunk->size());
805 ehc->e_shnum(_sectionHeaderChunk->count());
806
807 // I am pushing string section after all sections are in.
808 // Hence the index will be total number of non-custom sections we have
809
810 ehc->e_shstrndx(_sectionChunks.size() + 1);
811 _chunks.push_back(ehc);
812 _chunks.push_back(_sectionHeaderChunk);
813 // We have ELF header, section header. Now push rest of sections
814 for (auto chnk : _sectionChunks)
815 _chunks.push_back(chnk);
816 _chunks.push_back(_shstrtable);
817}
818
Sid Manningdd110202012-09-25 18:22:09 +0000819template<support::endianness target_endianness, bool is64Bits>
820void ELFWriter<target_endianness, is64Bits>
821 ::buildAtomToAddressMap () {
822
823// _atomToAddress is a DenseMap that maps an atom its file address.
824// std::get<1>(ai) is the offset from the start of the section to the atom.
825 for (auto &chunk : _sectionChunks){
826 for (auto &ai : chunk->atoms() ) {
827 _atomToAddress[std::get<0>(ai)] = chunk->address() + std::get<1>(ai);
828 }
829 }
830
831
832}
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000833
834template<support::endianness target_endianness, bool is64Bits>
835void ELFWriter<target_endianness, is64Bits>::assignFileOffsets() {
836 DEBUG_WITH_TYPE("WriterELF-layout", dbgs()
837 << "assign file offsets:\n");
838 uint64_t offset = 0;
839 uint64_t address = 0;
840 for (auto chunk : _chunks) {
841
842 chunk->assignFileOffset(offset, address);
843 }
844 //TODO: We need to fix all file offsets inside various ELF section headers
845 std::vector<Elf_Shdr*> secInfo = _sectionHeaderChunk->sectionInfo();
846 typename std::vector<Elf_Shdr*>::iterator it = secInfo.begin();
847 // First section is a NULL section with no sh_offset fix
848 (*it)->sh_offset = 0;
849 (*it)->sh_addr = 0;
850 ++it;
851 for (auto &chunk : _sectionChunks){
852 (*it)->sh_offset = chunk->fileOffset();
853 (*it)->sh_addr = chunk->address();
854 ++it;
855 }
856 // We have taken care of all the stock sections. We need to deal with
857 // custom sections
858 // They are section string table, string table and symbol table
859 (*it)->sh_offset = _shstrtable->fileOffset();
860 (*it)->sh_addr = _shstrtable->address();
861}
862
863template<support::endianness target_endianness, bool is64Bits>
864error_code ELFWriter<target_endianness, is64Bits>
865 ::writeFile(const lld::File &file, StringRef path) {
866 build(file);
867
868 uint64_t totalSize = _chunks.back()->fileOffset() + _chunks.back()->size();
869
870 OwningPtr<FileOutputBuffer> buffer;
871 error_code ec = FileOutputBuffer::create(path,
872 totalSize, buffer,
873 FileOutputBuffer::F_executable);
874 if (ec)
875 return ec;
876
877 for (auto chunk : _chunks) {
878 chunk->write(buffer->getBufferStart() + chunk->fileOffset());
879 }
880 return buffer->commit();
881}
Nick Kledzikabb69812012-05-31 22:34:00 +0000882
Sid Manningdd110202012-09-25 18:22:09 +0000883template<support::endianness target_endianness, bool is64Bits>
884uint64_t ELFWriter<target_endianness, is64Bits>
885 ::addressOfAtom(const Atom *atom) {
886 return _atomToAddress[atom];
887}
Nick Kledzikabb69812012-05-31 22:34:00 +0000888} // namespace elf
889
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000890Writer *createWriterELF(const WriterOptionsELF &options) {
891 if (!options.is64Bit() && options.endianness() == llvm::support::little)
892 return new lld::elf::ELFWriter<support::little, false>(options);
893 else if (options.is64Bit() && options.endianness() == llvm::support::little)
894 return new lld::elf::ELFWriter<support::little, true>(options);
895 else if (!options.is64Bit() && options.endianness() == llvm::support::big)
896 return new lld::elf::ELFWriter<support::big, false>(options);
897 else if (options.is64Bit() && options.endianness() == llvm::support::big)
898 return new lld::elf::ELFWriter<support::big, true>(options);
Nick Kledzikabb69812012-05-31 22:34:00 +0000899
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000900 llvm_unreachable("Invalid Options!");
Nick Kledzikabb69812012-05-31 22:34:00 +0000901}
902
903} // namespace lld