blob: 7030ee1102a6df08ebdcc8a1e8deace0a55d61dc [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);
428 // TODO Apply fixups to file buffer
429 }
430}
431//
432//===----------------------------------------------------------------------===//
433// ELFStringSectionChunk
434//===----------------------------------------------------------------------===//
435template<support::endianness target_endianness, bool is64Bits>
436ELFStringSectionChunk<target_endianness, is64Bits>::
437 ELFStringSectionChunk(const WriterOptionsELF &options,
438 ELFWriter<target_endianness, is64Bits> &writer,
439 StringRef secName)
440 : _segName("PT_NULL")
441 , _sectionName(secName)
442 , _writer(writer)
443 , _options(options) {
444 // First Add a null character. It also occupies 1 byte
445 _StringSection.emplace_back("");
446 this->_size = 1;
447}
448
449template<support::endianness target_endianness, bool is64Bits>
450uint64_t ELFStringSectionChunk<target_endianness, is64Bits>::
451 addString(StringRef symName) {
452 _StringSection.emplace_back(symName);
453
454 uint64_t offset = this->_size;
455 this->_size += symName.size() + 1;
456
457 return offset;
458}
459
460template<support::endianness target_endianness, bool is64Bits>
461const char *ELFStringSectionChunk<target_endianness, is64Bits>::info() {
462 return _sectionName.data();
463}
464
465template<support::endianness target_endianness, bool is64Bits>
466StringRef ELFStringSectionChunk<target_endianness, is64Bits>::sectionName() {
467 return _sectionName ;
468}
469
470template<support::endianness target_endianness, bool is64Bits>
471StringRef ELFStringSectionChunk<target_endianness, is64Bits>::
472 segmentName() const {
473 return _segName;
474}
475
476// We need to unwrap the _StringSection and then make one large memory
477// chunk of null terminated strings
478template<support::endianness target_endianness, bool is64Bits>
479void ELFStringSectionChunk<target_endianness, is64Bits>::
480 write(uint8_t *chunkBuffer) {
481 uint64_t chunkOffset = 0;
482
483 for (auto it : _StringSection) {
484 ::memcpy(chunkBuffer + chunkOffset, it.data(), it.size());
485 chunkOffset += it.size();
486 ::memcpy(chunkBuffer + chunkOffset, "", 1);
487 chunkOffset += 1;
488 }
489}
490
491//===----------------------------------------------------------------------===//
492// ELFHeaderChunk
493//===----------------------------------------------------------------------===//
494template<support::endianness target_endianness, bool is64Bits>
495ELFHeaderChunk<target_endianness, is64Bits>
496 ::ELFHeaderChunk(const WriterOptionsELF &options,
497 const File &File) {
498 this->_size = size();
499 e_ident(ELF::EI_MAG0, 0x7f);
500 e_ident(ELF::EI_MAG1, 'E');
501 e_ident(ELF::EI_MAG2, 'L');
502 e_ident(ELF::EI_MAG3, 'F');
503 e_ident(ELF::EI_CLASS, (options.is64Bit() ? ELF::ELFCLASS64
504 : ELF::ELFCLASS32));
505 e_ident(ELF::EI_DATA, options.endianness());
506 e_ident(ELF::EI_VERSION, 1);
507 e_ident(ELF::EI_OSABI, ELF::ELFOSABI_NONE);
508
509 e_type(options.type());
510 e_machine(options.machine());
511 e_version(1);
512
513 e_entry(0ULL);
514 e_phoff(this->_size);
515 e_shoff(0ULL);
516
517 e_flags(0);
518 e_ehsize(this->_size);
519 e_phentsize(0);
520 e_phnum(0);
521 e_shentsize(0);
522 e_shnum(0);
523 e_shstrndx(0);
524}
525
526template<support::endianness target_endianness, bool is64Bits>
527StringRef ELFHeaderChunk<target_endianness, is64Bits>
528 ::segmentName() const {
529 return "ELF";
530}
531
532template<support::endianness target_endianness, bool is64Bits>
533void ELFHeaderChunk<target_endianness, is64Bits>
534 ::write(uint8_t *chunkBuffer) {
535 ::memcpy(chunkBuffer, &_eh, size());
536}
537
538template<support::endianness target_endianness, bool is64Bits>
539const char *ELFHeaderChunk<target_endianness, is64Bits>::info() {
540 return "elf_header";
541}
542
543//===----------------------------------------------------------------------===//
544// ELFSectionHeaderChunk
545// List of Section Headers:
546//[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
547//[ 0] NULL 00000000 000000 000000 00 0 0 0
548//[ 1] .text PROGBITS 00000000 000034 000040 00 AX 0 0 4
549//===----------------------------------------------------------------------===//
550template<support::endianness target_endianness, bool is64Bits>
551ELFSectionHeaderChunk<target_endianness, is64Bits>
552 ::ELFSectionHeaderChunk(const WriterOptionsELF& options,
553 ELFWriter<target_endianness,
554 is64Bits> &writer)
555 : _options(options)
556 , _writer(writer) {
557
558 this->_size = 0;
559 this->_align2 = 0;
560 // The first element in the list is always NULL
561 Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
562 ::memset(nullshdr, 0, sizeof (Elf_Shdr));
563 _sectionInfo.push_back(nullshdr);
564
565 this->_size += sizeof (Elf_Shdr);
566
567 ELFStringSectionChunk<target_endianness, is64Bits> *str = _writer.shstrtab();
568
569 for (const auto &chunk : _writer.sectionChunks()) {
570 Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
571 StringRef Name = chunk->sectionName();
572 uint64_t offset = str->addString(Name);
573 shdr->sh_name = offset;
574 shdr->sh_type = chunk->type();
575 shdr->sh_flags = chunk->flags();
576 // TODO: At the time of creation of this section header, we will not have
577 // any address and offset info. We revisit this after assigning the file
578 // offsets.
579 shdr->sh_offset = chunk->fileOffset();
580 shdr->sh_addr = chunk->address();
581 shdr->sh_size = chunk->size();
582// The next two fields have special meanings:
583// sh_type sh_link sh_info
584// SHT_DYNAMIC The section header index of the string
585// table used by entries in the section. 0
586// SHT_HASH The section header index of the symbol
587// table to which the hash table applies. 0
588// SHT_REL
589// SHT_RELA The section header index of the
590// associated symbol table. The section header
591// index of the section
592// to which the
593// relocation applies.
594// SHT_SYMTAB
595// SHT_DYNSYM The section header index of the
596// associated string table. One greater than the
597// symbol table index of
598// the last local symbol
599// (binding STB_LOCAL).
600// SHT_GROUP The section header index of the
601// associated symbol table. The symbol table
602// index of an entry in
603// the associated symbol
604// table. The name of
605// the specified symbol
606// table entry provides
607// a signature for the
608// section group.
609// SHT_SYMTAB_SHNDX The section header index of
610// the associated symbol table section. 0
611// None of these chunks are of the above mentioned type, so we short them.
612 shdr->sh_link = 0;
613 shdr->sh_info = 0;
614 shdr->sh_addralign = chunk->align2();
615 // Not a special section with fixed entries
616 shdr->sh_entsize = 0;
617
618 _sectionInfo.push_back(shdr);
619 this->_size += sizeof (Elf_Shdr);
620 }
621
622 // Now I add in the section string table. For some reason This seems to be
623 // preferred location of string sections in contemporary
624 // (ones that must not be named) linker(s).
625 Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
626 // I push the name of the string table into the string table as soon as
627 // it is created.
628 shdr->sh_name = 1;
629 shdr->sh_type = ELF::SHT_STRTAB;
630 shdr->sh_flags = 0;
631 // NOTE: Refer to above note when assigning st_addr for other sections.
632 shdr->sh_addr = str->address();
633 shdr->sh_offset = str->fileOffset();
634 shdr->sh_size = str->size();
635 shdr->sh_link = 0;
636 shdr->sh_info = 0;
637 // This section is not a loadable section, hence we do not care about
638 // alignment.
639 shdr->sh_addralign = 1;
640 _sectionInfo.push_back(shdr);
641 this->_size += sizeof (Elf_Shdr);
642}
643
644template<support::endianness target_endianness, bool is64Bits>
645StringRef ELFSectionHeaderChunk<target_endianness, is64Bits>
646 ::segmentName() const {
647 return "SHDR";
648}
649
650template<support::endianness target_endianness, bool is64Bits>
651void ELFSectionHeaderChunk<target_endianness, is64Bits>
652 ::write(uint8_t *chunkBuffer) {
653 for (const auto si : _sectionInfo) {
654 ::memcpy(chunkBuffer, si, sizeof(*si));
655 chunkBuffer += sizeof (*si);
656 }
657}
658
659template<support::endianness target_endianness, bool is64Bits>
660uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::count() {
661 return _sectionInfo.size();
662}
663template<support::endianness target_endianness, bool is64Bits>
664uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::size() {
665 return sizeof (Elf_Shdr);
666}
667
668template<support::endianness target_endianness, bool is64Bits>
669const char *ELFSectionHeaderChunk<target_endianness, is64Bits>::info() {
670 return "elf_section_header";
671}
672
673//===----------------------------------------------------------------------===//
674// ELFProgramHeaderChunk
675//===----------------------------------------------------------------------===//
676// TODO: Implement the methods
677
678//===----------------------------------------------------------------------===//
679// ELFWriter Class
680//===----------------------------------------------------------------------===//
681template<support::endianness target_endianness, bool is64Bits>
682class ELFWriter : public Writer {
683public:
684 LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
685 typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
686 ELFWriter(const WriterOptionsELF &options);
687 virtual error_code writeFile(const lld::File &File, StringRef path);
688 ArrayRef<Chunk<target_endianness, is64Bits>*> chunks() { return _chunks; }
689 KindHandler *kindHandler() { return _referenceKindHandler; }
690
691 std::vector<SectionChunk<target_endianness, is64Bits>*> sectionChunks() {
692 return _sectionChunks ;
693 }
694
695 ELFStringSectionChunk<target_endianness, is64Bits> *shstrtab() {
696 return _shstrtable;
697 }
698
699private:
700 void build(const lld::File &file);
701 void createChunks(const lld::File &file);
702 void assignFileOffsets();
703 const WriterOptionsELF &_options;
704 ELFStringSectionChunk<target_endianness, is64Bits> *_shstrtable ;
705 std::unique_ptr<KindHandler> _referenceKindHandler;
706 ELFSectionHeaderChunk<target_endianness, is64Bits> *_sectionHeaderChunk;
707 std::vector<Chunk<target_endianness, is64Bits>*> _chunks;
708 const DefinedAtom *_entryAtom;
709 std::vector<SectionChunk<target_endianness, is64Bits>*> _sectionChunks;
710 llvm::BumpPtrAllocator _chunkAllocate;
711};
712
713//===----------------------------------------------------------------------===//
714// ELFWriter
715//===----------------------------------------------------------------------===//
716template<support::endianness target_endianness, bool is64Bits>
717ELFWriter<target_endianness, is64Bits>
718 ::ELFWriter(const WriterOptionsELF &options)
719 : _options(options)
720 , _referenceKindHandler(KindHandler::makeHandler(_options.machine()))
721{}
722
723template<support::endianness target_endianness, bool is64Bits>
724void ELFWriter<target_endianness, is64Bits>::build(const lld::File &file){
725 // Create objects for each chunk.
726 createChunks(file);
727 assignFileOffsets();
728}
729
730template<support::endianness target_endianness, bool is64Bits>
731void ELFWriter<target_endianness, is64Bits>
732 ::createChunks (const lld::File &file) {
733 std::map<StringRef, SectionChunk<target_endianness, is64Bits>*> sectionMap;
734
735 // We need to create hand crafted sections such as shstrtab strtab hash and
736 // symtab to put relevant information in ELF structures and then process the
737 // atoms.
738
739 _shstrtable = new (_chunkAllocate.Allocate
740 <ELFStringSectionChunk<target_endianness, is64Bits>>())
741 ELFStringSectionChunk<target_endianness, is64Bits>
742 (_options, *this, ".shstrtab");
743 _shstrtable->addString(".shstrtab");
744
745 //we also need to process undefined atoms
746 for (const DefinedAtom *a : file.defined() ) {
747 // TODO: Add sectionChoice.
748 // assert( atom->sectionChoice() == DefinedAtom::sectionBasedOnContent );
749 StringRef sectionName = a->customSectionName();
750 auto pos = sectionMap.find(sectionName);
751 DefinedAtom::ContentType type = a->contentType();
752 if (pos == sectionMap.end()) {
753 if (type != DefinedAtom::typeUnknown){
754 SectionChunk<target_endianness, is64Bits>
755 *chunk = new (_chunkAllocate.Allocate
756 <SectionChunk<target_endianness, is64Bits>>())
757 SectionChunk<target_endianness, is64Bits>
758 (type, sectionName, _options, *this);
759
760 sectionMap[sectionName] = chunk;
761 chunk->appendAtom(a);
762 _sectionChunks.push_back(chunk);
763 }
764 } else {
765 pos->second->appendAtom(a);
766 }
767 }
768
769 //put in the Undefined atoms as well
770 // Make header chunk
771 ELFHeaderChunk<target_endianness, is64Bits> *ehc =
772 new (_chunkAllocate.Allocate
773 <ELFHeaderChunk<target_endianness, is64Bits>>())
774 ELFHeaderChunk<target_endianness, is64Bits>(_options, file);
775
776 _sectionHeaderChunk = new (_chunkAllocate.Allocate<ELFSectionHeaderChunk
777 <target_endianness, is64Bits>>())
778 ELFSectionHeaderChunk
779 <target_endianness, is64Bits>(_options, *this);
780
781 ehc->e_shoff(ehc->size());
782 ehc->e_shentsize(_sectionHeaderChunk->size());
783 ehc->e_shnum(_sectionHeaderChunk->count());
784
785 // I am pushing string section after all sections are in.
786 // Hence the index will be total number of non-custom sections we have
787
788 ehc->e_shstrndx(_sectionChunks.size() + 1);
789 _chunks.push_back(ehc);
790 _chunks.push_back(_sectionHeaderChunk);
791 // We have ELF header, section header. Now push rest of sections
792 for (auto chnk : _sectionChunks)
793 _chunks.push_back(chnk);
794 _chunks.push_back(_shstrtable);
795}
796
797
798template<support::endianness target_endianness, bool is64Bits>
799void ELFWriter<target_endianness, is64Bits>::assignFileOffsets() {
800 DEBUG_WITH_TYPE("WriterELF-layout", dbgs()
801 << "assign file offsets:\n");
802 uint64_t offset = 0;
803 uint64_t address = 0;
804 for (auto chunk : _chunks) {
805
806 chunk->assignFileOffset(offset, address);
807 }
808 //TODO: We need to fix all file offsets inside various ELF section headers
809 std::vector<Elf_Shdr*> secInfo = _sectionHeaderChunk->sectionInfo();
810 typename std::vector<Elf_Shdr*>::iterator it = secInfo.begin();
811 // First section is a NULL section with no sh_offset fix
812 (*it)->sh_offset = 0;
813 (*it)->sh_addr = 0;
814 ++it;
815 for (auto &chunk : _sectionChunks){
816 (*it)->sh_offset = chunk->fileOffset();
817 (*it)->sh_addr = chunk->address();
818 ++it;
819 }
820 // We have taken care of all the stock sections. We need to deal with
821 // custom sections
822 // They are section string table, string table and symbol table
823 (*it)->sh_offset = _shstrtable->fileOffset();
824 (*it)->sh_addr = _shstrtable->address();
825}
826
827template<support::endianness target_endianness, bool is64Bits>
828error_code ELFWriter<target_endianness, is64Bits>
829 ::writeFile(const lld::File &file, StringRef path) {
830 build(file);
831
832 uint64_t totalSize = _chunks.back()->fileOffset() + _chunks.back()->size();
833
834 OwningPtr<FileOutputBuffer> buffer;
835 error_code ec = FileOutputBuffer::create(path,
836 totalSize, buffer,
837 FileOutputBuffer::F_executable);
838 if (ec)
839 return ec;
840
841 for (auto chunk : _chunks) {
842 chunk->write(buffer->getBufferStart() + chunk->fileOffset());
843 }
844 return buffer->commit();
845}
Nick Kledzikabb69812012-05-31 22:34:00 +0000846
847} // namespace elf
848
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000849Writer *createWriterELF(const WriterOptionsELF &options) {
850 if (!options.is64Bit() && options.endianness() == llvm::support::little)
851 return new lld::elf::ELFWriter<support::little, false>(options);
852 else if (options.is64Bit() && options.endianness() == llvm::support::little)
853 return new lld::elf::ELFWriter<support::little, true>(options);
854 else if (!options.is64Bit() && options.endianness() == llvm::support::big)
855 return new lld::elf::ELFWriter<support::big, false>(options);
856 else if (options.is64Bit() && options.endianness() == llvm::support::big)
857 return new lld::elf::ELFWriter<support::big, true>(options);
Nick Kledzikabb69812012-05-31 22:34:00 +0000858
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000859 llvm_unreachable("Invalid Options!");
Nick Kledzikabb69812012-05-31 22:34:00 +0000860}
861
862} // namespace lld