blob: 139f5bd4a5b8cbc380f5f2409915d8d1c1c9d567 [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";
Sid Manningd3a7e7e2012-09-26 22:46:17 +0000332 _sectionName = sectionName;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000333 _flags = ELF::SHF_ALLOC | ELF::SHF_WRITE;
334 _type = ELF::SHT_NOBITS;
335 break;
Sid Manningd3a7e7e2012-09-26 22:46:17 +0000336 case DefinedAtom::typeConstant:
337 _segmentName = "PT_LOAD";
338 _sectionName = sectionName;
339 _flags = ELF::SHF_ALLOC;
340 _type = ELF::SHT_PROGBITS;
341 break;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000342 default:
343 llvm_unreachable("Unhandled content type for section!");
344 }
345}
346
347template<support::endianness target_endianness, bool is64Bits>
348bool SectionChunk<target_endianness, is64Bits>::occupiesNoDiskSpace() {
349 return false;
350}
351
352template<support::endianness target_endianness, bool is64Bits>
353StringRef SectionChunk<target_endianness, is64Bits>::segmentName() const {
354 return _segmentName;
355}
356
357template<support::endianness target_endianness, bool is64Bits>
358StringRef SectionChunk<target_endianness, is64Bits>::sectionName() {
359 return _sectionName;
360}
361
362template<support::endianness target_endianness, bool is64Bits>
363uint32_t SectionChunk<target_endianness, is64Bits>::flags() const {
364 return _flags;
365}
366
367template<support::endianness target_endianness, bool is64Bits>
368uint32_t SectionChunk<target_endianness, is64Bits>::type() const {
369 return _type;
370}
371
372template<support::endianness target_endianness, bool is64Bits>
373uint32_t SectionChunk<target_endianness, is64Bits>::permissions() {
374 return _permissions;
375}
376
377template<support::endianness target_endianness, bool is64Bits>
378const char *SectionChunk<target_endianness, is64Bits>::info() {
379 return _sectionName.data();
380}
381
382template<support::endianness target_endianness, bool is64Bits>
383const ArrayRef<AtomInfo> SectionChunk<target_endianness, is64Bits>::
384 atoms() const {
385 return _atoms;
386}
387
388
389template<support::endianness target_endianness, bool is64Bits>
390void SectionChunk<target_endianness, is64Bits>::
391 appendAtom(const DefinedAtom *atom) {
392 // Figure out offset for atom in this section given alignment constraints.
393 uint64_t offset = this->_size;
394 DefinedAtom::Alignment atomAlign = atom->alignment();
395 uint64_t align2 = 1 << atomAlign.powerOf2;
396 uint64_t requiredModulus = atomAlign.modulus;
397 uint64_t currentModulus = (offset % align2);
398 if (currentModulus != requiredModulus) {
399 if (requiredModulus > currentModulus)
400 offset += requiredModulus - currentModulus;
401 else
402 offset += align2 + requiredModulus - currentModulus;
403 }
404 // Record max alignment of any atom in this section.
405 if (align2 > this->_align2)
406 this->_align2 = align2;
407 // Assign atom to this section with this offset.
408 _atoms.emplace_back(atom, offset);
409 // Update section size to include this atom.
410 this->_size = offset + atom->size();
411 // Update permissions
412 DefinedAtom::ContentPermissions perms = atom->permissions();
413
414 // TODO: Check content permissions and figure out what to do with .bss
415 if ((perms & DefinedAtom::permR__) == DefinedAtom::permR__)
416 this->_permissions |= ELF::SHF_ALLOC;
417 if ((perms & DefinedAtom::permRW_) == DefinedAtom::permRW_)
418 this->_permissions |= (ELF::SHF_ALLOC | ELF::SHF_WRITE);
419 if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
420 this->_permissions |= (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
421}
422
423template<support::endianness target_endianness, bool is64Bits>
424void SectionChunk<target_endianness, is64Bits>::write(uint8_t *chunkBuffer) {
425 // Each section's content is just its atoms' content.
426 for (const auto &ai : _atoms ) {
427 // Copy raw content of atom to file buffer.
428 ArrayRef<uint8_t> content = std::get<0>(ai)->rawContent();
429 uint64_t contentSize = content.size();
430 if (contentSize == 0)
431 continue;
432 uint8_t *atomContent = chunkBuffer + std::get<1>(ai);
433 std::copy_n(content.data(), contentSize, atomContent);
Sid Manningdd110202012-09-25 18:22:09 +0000434
435 for (const Reference *ref : *std::get<0>(ai)){
436 uint32_t offset = ref->offsetInAtom();
437 uint64_t targetAddress = 0;
438
439 if ( ref->target() != nullptr )
440 targetAddress = _writer.addressOfAtom(ref->target());
441
442 uint64_t fixupAddress = _writer.addressOfAtom(std::get<0>(ai)) + offset;
443 _writer.kindHandler()->applyFixup(ref->kind(), ref->addend(),
444 &atomContent[offset],
445 fixupAddress,
446 targetAddress);
447 }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000448 }
449}
450//
451//===----------------------------------------------------------------------===//
452// ELFStringSectionChunk
453//===----------------------------------------------------------------------===//
454template<support::endianness target_endianness, bool is64Bits>
455ELFStringSectionChunk<target_endianness, is64Bits>::
456 ELFStringSectionChunk(const WriterOptionsELF &options,
457 ELFWriter<target_endianness, is64Bits> &writer,
458 StringRef secName)
459 : _segName("PT_NULL")
460 , _sectionName(secName)
461 , _writer(writer)
462 , _options(options) {
463 // First Add a null character. It also occupies 1 byte
464 _StringSection.emplace_back("");
465 this->_size = 1;
466}
467
468template<support::endianness target_endianness, bool is64Bits>
469uint64_t ELFStringSectionChunk<target_endianness, is64Bits>::
470 addString(StringRef symName) {
471 _StringSection.emplace_back(symName);
472
473 uint64_t offset = this->_size;
474 this->_size += symName.size() + 1;
475
476 return offset;
477}
478
479template<support::endianness target_endianness, bool is64Bits>
480const char *ELFStringSectionChunk<target_endianness, is64Bits>::info() {
481 return _sectionName.data();
482}
483
484template<support::endianness target_endianness, bool is64Bits>
485StringRef ELFStringSectionChunk<target_endianness, is64Bits>::sectionName() {
486 return _sectionName ;
487}
488
489template<support::endianness target_endianness, bool is64Bits>
490StringRef ELFStringSectionChunk<target_endianness, is64Bits>::
491 segmentName() const {
492 return _segName;
493}
494
495// We need to unwrap the _StringSection and then make one large memory
496// chunk of null terminated strings
497template<support::endianness target_endianness, bool is64Bits>
498void ELFStringSectionChunk<target_endianness, is64Bits>::
499 write(uint8_t *chunkBuffer) {
500 uint64_t chunkOffset = 0;
501
502 for (auto it : _StringSection) {
503 ::memcpy(chunkBuffer + chunkOffset, it.data(), it.size());
504 chunkOffset += it.size();
505 ::memcpy(chunkBuffer + chunkOffset, "", 1);
506 chunkOffset += 1;
507 }
508}
509
510//===----------------------------------------------------------------------===//
511// ELFHeaderChunk
512//===----------------------------------------------------------------------===//
513template<support::endianness target_endianness, bool is64Bits>
514ELFHeaderChunk<target_endianness, is64Bits>
515 ::ELFHeaderChunk(const WriterOptionsELF &options,
516 const File &File) {
517 this->_size = size();
518 e_ident(ELF::EI_MAG0, 0x7f);
519 e_ident(ELF::EI_MAG1, 'E');
520 e_ident(ELF::EI_MAG2, 'L');
521 e_ident(ELF::EI_MAG3, 'F');
522 e_ident(ELF::EI_CLASS, (options.is64Bit() ? ELF::ELFCLASS64
523 : ELF::ELFCLASS32));
524 e_ident(ELF::EI_DATA, options.endianness());
525 e_ident(ELF::EI_VERSION, 1);
526 e_ident(ELF::EI_OSABI, ELF::ELFOSABI_NONE);
527
528 e_type(options.type());
529 e_machine(options.machine());
530 e_version(1);
531
532 e_entry(0ULL);
533 e_phoff(this->_size);
534 e_shoff(0ULL);
535
536 e_flags(0);
537 e_ehsize(this->_size);
538 e_phentsize(0);
539 e_phnum(0);
540 e_shentsize(0);
541 e_shnum(0);
542 e_shstrndx(0);
543}
544
545template<support::endianness target_endianness, bool is64Bits>
546StringRef ELFHeaderChunk<target_endianness, is64Bits>
547 ::segmentName() const {
548 return "ELF";
549}
550
551template<support::endianness target_endianness, bool is64Bits>
552void ELFHeaderChunk<target_endianness, is64Bits>
553 ::write(uint8_t *chunkBuffer) {
554 ::memcpy(chunkBuffer, &_eh, size());
555}
556
557template<support::endianness target_endianness, bool is64Bits>
558const char *ELFHeaderChunk<target_endianness, is64Bits>::info() {
559 return "elf_header";
560}
561
562//===----------------------------------------------------------------------===//
563// ELFSectionHeaderChunk
564// List of Section Headers:
565//[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
566//[ 0] NULL 00000000 000000 000000 00 0 0 0
567//[ 1] .text PROGBITS 00000000 000034 000040 00 AX 0 0 4
568//===----------------------------------------------------------------------===//
569template<support::endianness target_endianness, bool is64Bits>
570ELFSectionHeaderChunk<target_endianness, is64Bits>
571 ::ELFSectionHeaderChunk(const WriterOptionsELF& options,
572 ELFWriter<target_endianness,
573 is64Bits> &writer)
574 : _options(options)
575 , _writer(writer) {
576
577 this->_size = 0;
578 this->_align2 = 0;
579 // The first element in the list is always NULL
580 Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
581 ::memset(nullshdr, 0, sizeof (Elf_Shdr));
582 _sectionInfo.push_back(nullshdr);
583
584 this->_size += sizeof (Elf_Shdr);
585
586 ELFStringSectionChunk<target_endianness, is64Bits> *str = _writer.shstrtab();
587
588 for (const auto &chunk : _writer.sectionChunks()) {
589 Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
590 StringRef Name = chunk->sectionName();
591 uint64_t offset = str->addString(Name);
592 shdr->sh_name = offset;
593 shdr->sh_type = chunk->type();
594 shdr->sh_flags = chunk->flags();
595 // TODO: At the time of creation of this section header, we will not have
596 // any address and offset info. We revisit this after assigning the file
597 // offsets.
598 shdr->sh_offset = chunk->fileOffset();
599 shdr->sh_addr = chunk->address();
600 shdr->sh_size = chunk->size();
601// The next two fields have special meanings:
602// sh_type sh_link sh_info
603// SHT_DYNAMIC The section header index of the string
604// table used by entries in the section. 0
605// SHT_HASH The section header index of the symbol
606// table to which the hash table applies. 0
607// SHT_REL
608// SHT_RELA The section header index of the
609// associated symbol table. The section header
610// index of the section
611// to which the
612// relocation applies.
613// SHT_SYMTAB
614// SHT_DYNSYM The section header index of the
615// associated string table. One greater than the
616// symbol table index of
617// the last local symbol
618// (binding STB_LOCAL).
619// SHT_GROUP The section header index of the
620// associated symbol table. The symbol table
621// index of an entry in
622// the associated symbol
623// table. The name of
624// the specified symbol
625// table entry provides
626// a signature for the
627// section group.
628// SHT_SYMTAB_SHNDX The section header index of
629// the associated symbol table section. 0
630// None of these chunks are of the above mentioned type, so we short them.
631 shdr->sh_link = 0;
632 shdr->sh_info = 0;
633 shdr->sh_addralign = chunk->align2();
634 // Not a special section with fixed entries
635 shdr->sh_entsize = 0;
636
637 _sectionInfo.push_back(shdr);
638 this->_size += sizeof (Elf_Shdr);
639 }
640
641 // Now I add in the section string table. For some reason This seems to be
642 // preferred location of string sections in contemporary
643 // (ones that must not be named) linker(s).
644 Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
645 // I push the name of the string table into the string table as soon as
646 // it is created.
647 shdr->sh_name = 1;
648 shdr->sh_type = ELF::SHT_STRTAB;
649 shdr->sh_flags = 0;
650 // NOTE: Refer to above note when assigning st_addr for other sections.
651 shdr->sh_addr = str->address();
652 shdr->sh_offset = str->fileOffset();
653 shdr->sh_size = str->size();
654 shdr->sh_link = 0;
655 shdr->sh_info = 0;
656 // This section is not a loadable section, hence we do not care about
657 // alignment.
658 shdr->sh_addralign = 1;
659 _sectionInfo.push_back(shdr);
660 this->_size += sizeof (Elf_Shdr);
661}
662
663template<support::endianness target_endianness, bool is64Bits>
664StringRef ELFSectionHeaderChunk<target_endianness, is64Bits>
665 ::segmentName() const {
666 return "SHDR";
667}
668
669template<support::endianness target_endianness, bool is64Bits>
670void ELFSectionHeaderChunk<target_endianness, is64Bits>
671 ::write(uint8_t *chunkBuffer) {
672 for (const auto si : _sectionInfo) {
673 ::memcpy(chunkBuffer, si, sizeof(*si));
674 chunkBuffer += sizeof (*si);
675 }
676}
677
678template<support::endianness target_endianness, bool is64Bits>
679uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::count() {
680 return _sectionInfo.size();
681}
682template<support::endianness target_endianness, bool is64Bits>
683uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::size() {
684 return sizeof (Elf_Shdr);
685}
686
687template<support::endianness target_endianness, bool is64Bits>
688const char *ELFSectionHeaderChunk<target_endianness, is64Bits>::info() {
689 return "elf_section_header";
690}
691
692//===----------------------------------------------------------------------===//
693// ELFProgramHeaderChunk
694//===----------------------------------------------------------------------===//
695// TODO: Implement the methods
696
697//===----------------------------------------------------------------------===//
698// ELFWriter Class
699//===----------------------------------------------------------------------===//
700template<support::endianness target_endianness, bool is64Bits>
701class ELFWriter : public Writer {
702public:
703 LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
704 typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
705 ELFWriter(const WriterOptionsELF &options);
706 virtual error_code writeFile(const lld::File &File, StringRef path);
Sid Manningdd110202012-09-25 18:22:09 +0000707 uint64_t addressOfAtom(const Atom *atom);
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000708 ArrayRef<Chunk<target_endianness, is64Bits>*> chunks() { return _chunks; }
Sid Manningdd110202012-09-25 18:22:09 +0000709 KindHandler *kindHandler() { return _referenceKindHandler.get(); }
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000710
711 std::vector<SectionChunk<target_endianness, is64Bits>*> sectionChunks() {
712 return _sectionChunks ;
713 }
714
715 ELFStringSectionChunk<target_endianness, is64Bits> *shstrtab() {
716 return _shstrtable;
717 }
718
719private:
720 void build(const lld::File &file);
721 void createChunks(const lld::File &file);
Sid Manningdd110202012-09-25 18:22:09 +0000722 void buildAtomToAddressMap();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000723 void assignFileOffsets();
724 const WriterOptionsELF &_options;
Sid Manningdd110202012-09-25 18:22:09 +0000725
726/// \brief AtomToAddress: Is a mapping from an Atom to the address where
727/// it will live in the output file.
728 typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
729
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000730 ELFStringSectionChunk<target_endianness, is64Bits> *_shstrtable ;
731 std::unique_ptr<KindHandler> _referenceKindHandler;
732 ELFSectionHeaderChunk<target_endianness, is64Bits> *_sectionHeaderChunk;
Sid Manningdd110202012-09-25 18:22:09 +0000733 AtomToAddress _atomToAddress;
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000734 std::vector<Chunk<target_endianness, is64Bits>*> _chunks;
735 const DefinedAtom *_entryAtom;
736 std::vector<SectionChunk<target_endianness, is64Bits>*> _sectionChunks;
737 llvm::BumpPtrAllocator _chunkAllocate;
738};
739
740//===----------------------------------------------------------------------===//
741// ELFWriter
742//===----------------------------------------------------------------------===//
743template<support::endianness target_endianness, bool is64Bits>
744ELFWriter<target_endianness, is64Bits>
745 ::ELFWriter(const WriterOptionsELF &options)
746 : _options(options)
747 , _referenceKindHandler(KindHandler::makeHandler(_options.machine()))
748{}
749
750template<support::endianness target_endianness, bool is64Bits>
751void ELFWriter<target_endianness, is64Bits>::build(const lld::File &file){
752 // Create objects for each chunk.
753 createChunks(file);
754 assignFileOffsets();
Sid Manningdd110202012-09-25 18:22:09 +0000755 buildAtomToAddressMap();
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000756}
757
758template<support::endianness target_endianness, bool is64Bits>
759void ELFWriter<target_endianness, is64Bits>
760 ::createChunks (const lld::File &file) {
761 std::map<StringRef, SectionChunk<target_endianness, is64Bits>*> sectionMap;
762
763 // We need to create hand crafted sections such as shstrtab strtab hash and
764 // symtab to put relevant information in ELF structures and then process the
765 // atoms.
766
767 _shstrtable = new (_chunkAllocate.Allocate
768 <ELFStringSectionChunk<target_endianness, is64Bits>>())
769 ELFStringSectionChunk<target_endianness, is64Bits>
770 (_options, *this, ".shstrtab");
771 _shstrtable->addString(".shstrtab");
772
773 //we also need to process undefined atoms
774 for (const DefinedAtom *a : file.defined() ) {
775 // TODO: Add sectionChoice.
776 // assert( atom->sectionChoice() == DefinedAtom::sectionBasedOnContent );
777 StringRef sectionName = a->customSectionName();
778 auto pos = sectionMap.find(sectionName);
779 DefinedAtom::ContentType type = a->contentType();
780 if (pos == sectionMap.end()) {
781 if (type != DefinedAtom::typeUnknown){
782 SectionChunk<target_endianness, is64Bits>
783 *chunk = new (_chunkAllocate.Allocate
784 <SectionChunk<target_endianness, is64Bits>>())
785 SectionChunk<target_endianness, is64Bits>
786 (type, sectionName, _options, *this);
787
788 sectionMap[sectionName] = chunk;
789 chunk->appendAtom(a);
790 _sectionChunks.push_back(chunk);
791 }
792 } else {
793 pos->second->appendAtom(a);
794 }
795 }
796
797 //put in the Undefined atoms as well
798 // Make header chunk
799 ELFHeaderChunk<target_endianness, is64Bits> *ehc =
800 new (_chunkAllocate.Allocate
801 <ELFHeaderChunk<target_endianness, is64Bits>>())
802 ELFHeaderChunk<target_endianness, is64Bits>(_options, file);
803
804 _sectionHeaderChunk = new (_chunkAllocate.Allocate<ELFSectionHeaderChunk
805 <target_endianness, is64Bits>>())
806 ELFSectionHeaderChunk
807 <target_endianness, is64Bits>(_options, *this);
808
809 ehc->e_shoff(ehc->size());
810 ehc->e_shentsize(_sectionHeaderChunk->size());
811 ehc->e_shnum(_sectionHeaderChunk->count());
812
813 // I am pushing string section after all sections are in.
814 // Hence the index will be total number of non-custom sections we have
815
816 ehc->e_shstrndx(_sectionChunks.size() + 1);
817 _chunks.push_back(ehc);
818 _chunks.push_back(_sectionHeaderChunk);
819 // We have ELF header, section header. Now push rest of sections
820 for (auto chnk : _sectionChunks)
821 _chunks.push_back(chnk);
822 _chunks.push_back(_shstrtable);
823}
824
Sid Manningdd110202012-09-25 18:22:09 +0000825template<support::endianness target_endianness, bool is64Bits>
826void ELFWriter<target_endianness, is64Bits>
827 ::buildAtomToAddressMap () {
828
829// _atomToAddress is a DenseMap that maps an atom its file address.
830// std::get<1>(ai) is the offset from the start of the section to the atom.
831 for (auto &chunk : _sectionChunks){
832 for (auto &ai : chunk->atoms() ) {
833 _atomToAddress[std::get<0>(ai)] = chunk->address() + std::get<1>(ai);
834 }
835 }
836
837
838}
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000839
840template<support::endianness target_endianness, bool is64Bits>
841void ELFWriter<target_endianness, is64Bits>::assignFileOffsets() {
842 DEBUG_WITH_TYPE("WriterELF-layout", dbgs()
843 << "assign file offsets:\n");
844 uint64_t offset = 0;
845 uint64_t address = 0;
846 for (auto chunk : _chunks) {
847
848 chunk->assignFileOffset(offset, address);
849 }
850 //TODO: We need to fix all file offsets inside various ELF section headers
851 std::vector<Elf_Shdr*> secInfo = _sectionHeaderChunk->sectionInfo();
852 typename std::vector<Elf_Shdr*>::iterator it = secInfo.begin();
853 // First section is a NULL section with no sh_offset fix
854 (*it)->sh_offset = 0;
855 (*it)->sh_addr = 0;
856 ++it;
857 for (auto &chunk : _sectionChunks){
858 (*it)->sh_offset = chunk->fileOffset();
859 (*it)->sh_addr = chunk->address();
860 ++it;
861 }
862 // We have taken care of all the stock sections. We need to deal with
863 // custom sections
864 // They are section string table, string table and symbol table
865 (*it)->sh_offset = _shstrtable->fileOffset();
866 (*it)->sh_addr = _shstrtable->address();
867}
868
869template<support::endianness target_endianness, bool is64Bits>
870error_code ELFWriter<target_endianness, is64Bits>
871 ::writeFile(const lld::File &file, StringRef path) {
872 build(file);
873
874 uint64_t totalSize = _chunks.back()->fileOffset() + _chunks.back()->size();
875
876 OwningPtr<FileOutputBuffer> buffer;
877 error_code ec = FileOutputBuffer::create(path,
878 totalSize, buffer,
879 FileOutputBuffer::F_executable);
880 if (ec)
881 return ec;
882
883 for (auto chunk : _chunks) {
884 chunk->write(buffer->getBufferStart() + chunk->fileOffset());
885 }
886 return buffer->commit();
887}
Nick Kledzikabb69812012-05-31 22:34:00 +0000888
Sid Manningdd110202012-09-25 18:22:09 +0000889template<support::endianness target_endianness, bool is64Bits>
890uint64_t ELFWriter<target_endianness, is64Bits>
891 ::addressOfAtom(const Atom *atom) {
892 return _atomToAddress[atom];
893}
Nick Kledzikabb69812012-05-31 22:34:00 +0000894} // namespace elf
895
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000896Writer *createWriterELF(const WriterOptionsELF &options) {
897 if (!options.is64Bit() && options.endianness() == llvm::support::little)
898 return new lld::elf::ELFWriter<support::little, false>(options);
899 else if (options.is64Bit() && options.endianness() == llvm::support::little)
900 return new lld::elf::ELFWriter<support::little, true>(options);
901 else if (!options.is64Bit() && options.endianness() == llvm::support::big)
902 return new lld::elf::ELFWriter<support::big, false>(options);
903 else if (options.is64Bit() && options.endianness() == llvm::support::big)
904 return new lld::elf::ELFWriter<support::big, true>(options);
Nick Kledzikabb69812012-05-31 22:34:00 +0000905
Hemant Kulkarni927bbc22012-09-14 16:11:34 +0000906 llvm_unreachable("Invalid Options!");
Nick Kledzikabb69812012-05-31 22:34:00 +0000907}
908
909} // namespace lld