blob: f6c46c6492442fec5fe122bddafa92f21fedca43 [file] [log] [blame]
Michael J. Spencere68f9032013-01-29 22:03:39 +00001//===- lib/ReaderWriter/ELF/SectionChunks.h -------------------------------===//
Shankar Easwaran6d9921f2013-01-21 20:09:55 +00002//
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
Michael J. Spencere68f9032013-01-29 22:03:39 +000010#ifndef LLD_READER_WRITER_ELF_SECTION_CHUNKS_H
11#define LLD_READER_WRITER_ELF_SECTION_CHUNKS_H
Shankar Easwaran6d9921f2013-01-21 20:09:55 +000012
Michael J. Spencere68f9032013-01-29 22:03:39 +000013#include "Chunk.h"
14#include "Layout.h"
15#include "TargetHandler.h"
16#include "Writer.h"
Michael J. Spencer43ecac52013-01-29 19:53:41 +000017
Shankar Easwaran6d9921f2013-01-21 20:09:55 +000018#include "lld/Core/DefinedAtom.h"
19#include "lld/Core/range.h"
20
21#include "llvm/ADT/ArrayRef.h"
22#include "llvm/ADT/OwningPtr.h"
23#include "llvm/ADT/StringRef.h"
Shankar Easwaran6d9921f2013-01-21 20:09:55 +000024#include "llvm/Object/ELF.h"
Shankar Easwaran6d9921f2013-01-21 20:09:55 +000025#include "llvm/Support/Allocator.h"
26#include "llvm/Support/Debug.h"
27#include "llvm/Support/ELF.h"
28#include "llvm/Support/ErrorHandling.h"
29#include "llvm/Support/FileOutputBuffer.h"
30
Shankar Easwaran6d9921f2013-01-21 20:09:55 +000031namespace lld {
32namespace elf {
33
34/// \brief A section contains a set of atoms that have similiar properties
35/// The atoms that have similiar properties are merged to form a section
36template<class ELFT>
37class Section : public Chunk<ELFT> {
38public:
39 // The Kind of section that the object represents
40 enum SectionKind {
41 K_Default,
42 K_Target, // The section is handed over to the target
43 K_SymbolTable,
44 K_StringTable,
45 };
46 // Create a section object, the section is set to the default type if the
47 // caller doesnot set it
Shankar Easwarana6f00fe2013-01-30 07:11:43 +000048 Section(const ELFTargetInfo &, StringRef sectionName,
Michael J. Spencerbf77be32013-01-29 01:07:47 +000049 const int32_t contentType, const int32_t contentPermissions,
50 const int32_t order, const SectionKind kind = K_Default);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +000051
52 /// return the section kind
53 inline SectionKind sectionKind() const {
54 return _sectionKind;
55 }
56
Shankar Easwarana6f00fe2013-01-30 07:11:43 +000057 /// set the section Kind, this function is needed by the targetHandler
58 /// to set the target section
59 inline void setKind(SectionKind k) { _sectionKind = k; }
60
61 /// Is the section part of any segment, Target sections must override
62 /// this function
63 virtual bool hasOutputSegment() {
64 assert((_sectionKind != K_Target) &&
65 "Cannot determine if the targetSection has any output segment");
66 return false;
67 }
68
Shankar Easwaran6d9921f2013-01-21 20:09:55 +000069 /// Align the offset to the required modulus defined by the atom alignment
70 uint64_t alignOffset(uint64_t offset, DefinedAtom::Alignment &atomAlign);
71
72 // \brief Append an atom to a Section. The atom gets pushed into a vector
73 // contains the atom, the atom file offset, the atom virtual address
74 // the atom file offset is aligned appropriately as set by the Reader
Michael J. Spencer42606572013-01-30 01:25:06 +000075 const AtomLayout &appendAtom(const Atom *atom);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +000076
77 /// \brief Set the virtual address of each Atom in the Section. This
78 /// routine gets called after the linker fixes up the virtual address
79 /// of the section
80 inline void assignVirtualAddress(uint64_t &addr) {
81 for (auto &ai : _atoms) {
Michael J. Spencer42606572013-01-30 01:25:06 +000082 ai->_virtualAddr = addr + ai->_fileOffset;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +000083 }
84 addr += this->memSize();
85 }
86
87 /// \brief Set the file offset of each Atom in the section. This routine
88 /// gets called after the linker fixes up the section offset
89 inline void assignOffsets(uint64_t offset) {
90 for (auto &ai : _atoms) {
Michael J. Spencer42606572013-01-30 01:25:06 +000091 ai->_fileOffset = offset + ai->_fileOffset;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +000092 }
93 }
94
95 /// \brief Find the Atom address given a name, this is needed to to properly
96 /// apply relocation. The section class calls this to find the atom address
97 /// to fix the relocation
Shankar Easwarana6f00fe2013-01-30 07:11:43 +000098 inline bool findAtomAddrByName(StringRef name, uint64_t &addr) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +000099 for (auto ai : _atoms) {
Michael J. Spencer42606572013-01-30 01:25:06 +0000100 if (ai->_atom->name() == name) {
101 addr = ai->_virtualAddr;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000102 return true;
103 }
104 }
105 return false;
106 }
107
108 /// \brief Does the Atom occupy any disk space
109 inline bool occupiesNoDiskSpace() const {
110 return _contentType == DefinedAtom::typeZeroFill;
111 }
112
113 /// \brief The permission of the section is the most permissive permission
114 /// of all atoms that the section contains
115 inline void setContentPermissions(int32_t perm) {
116 _contentPermissions = std::max(perm, _contentPermissions);
117 }
118
119 /// \brief Get the section flags, defined by the permissions of the section
120 int64_t flags();
121
122 /// \brief Return the section type, the returned value is recorded in the
123 /// sh_type field of the Section Header
124 int type();
125
126 /// \brief convert the segment type to a String for diagnostics
127 /// and printing purposes
Michael J. Spencere68f9032013-01-29 22:03:39 +0000128 StringRef segmentKindToStr() const;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000129
130 /// \brief Return the raw flags, we need this to sort segments
131 inline int64_t atomflags() const {
132 return _contentPermissions;
133 }
134
135 /// \brief Returns the section link field, the returned value is
136 /// recorded in the sh_link field of the Section Header
137 inline int link() const {
138 return _link;
139 }
140
141 inline void setLink(int32_t link) {
142 _link = link;
143 }
144
145 /// \brief Returns the section entsize field, the returned value is
146 /// recorded in the sh_entsize field of the Section Header
147 inline int entsize() const {
148 return _entSize;
149 }
150
151 /// \brief Returns the shinfo field, the returned value is
152 /// recorded in the sh_info field of the Section Header
153 inline int shinfo() const {
154 return _shInfo;
155 }
156
157 /// \brief Records the segmentType, that this section belongs to
Michael J. Spencere68f9032013-01-29 22:03:39 +0000158 inline void setSegment(const Layout::SegmentType segmentType) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000159 _segmentType = segmentType;
160 }
161
162 /// \brief for LLVM style RTTI information
163 static inline bool classof(const Chunk<ELFT> *c) {
164 return c->kind() == Chunk<ELFT>::K_ELFSection;
165 }
166
167 /// \brief Finalize the section contents before writing
168 inline void finalize() { }
169
170 /// \brief Write the section and the atom contents to the buffer
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000171 void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000172
173 /// Atom Iterators
Michael J. Spencer42606572013-01-30 01:25:06 +0000174 typedef typename std::vector<AtomLayout *>::iterator atom_iter;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000175
176 range<atom_iter> atoms() { return _atoms; }
177
178protected:
179 int32_t _contentType;
180 int32_t _contentPermissions;
181 SectionKind _sectionKind;
Michael J. Spencer42606572013-01-30 01:25:06 +0000182 std::vector<AtomLayout *> _atoms;
Michael J. Spencere68f9032013-01-29 22:03:39 +0000183 Layout::SegmentType _segmentType;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000184 int64_t _entSize;
185 int64_t _shInfo;
186 int64_t _link;
Michael J. Spencer42606572013-01-30 01:25:06 +0000187 llvm::BumpPtrAllocator _alloc;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000188};
189
190// Create a section object, the section is set to the default type if the
191// caller doesnot set it
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000192template <class ELFT>
Shankar Easwarana6f00fe2013-01-30 07:11:43 +0000193Section<ELFT>::Section(const ELFTargetInfo &ti, StringRef sectionName,
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000194 const int32_t contentType,
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000195 const int32_t contentPermissions, const int32_t order,
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000196 const SectionKind kind)
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000197 : Chunk<ELFT>(sectionName, Chunk<ELFT>::K_ELFSection, ti),
198 _contentType(contentType), _contentPermissions(contentPermissions),
199 _sectionKind(kind), _entSize(0), _shInfo(0), _link(0) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000200 this->setOrder(order);
201}
202
203/// Align the offset to the required modulus defined by the atom alignment
204template<class ELFT>
205uint64_t
206Section<ELFT>::alignOffset(uint64_t offset, DefinedAtom::Alignment &atomAlign) {
207 uint64_t requiredModulus = atomAlign.modulus;
208 uint64_t align2 = 1u << atomAlign.powerOf2;
209 uint64_t currentModulus = (offset % align2);
210 uint64_t retOffset = offset;
211 if (currentModulus != requiredModulus) {
212 if (requiredModulus > currentModulus)
213 retOffset += requiredModulus - currentModulus;
214 else
215 retOffset += align2 + requiredModulus - currentModulus;
216 }
217 return retOffset;
218}
219
220// \brief Append an atom to a Section. The atom gets pushed into a vector
221// contains the atom, the atom file offset, the atom virtual address
222// the atom file offset is aligned appropriately as set by the Reader
Michael J. Spencer42606572013-01-30 01:25:06 +0000223template <class ELFT>
224const AtomLayout &Section<ELFT>::appendAtom(const Atom *atom) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000225 Atom::Definition atomType = atom->definition();
226 const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
227
228 DefinedAtom::Alignment atomAlign = definedAtom->alignment();
229 uint64_t align2 = 1u << atomAlign.powerOf2;
230 // Align the atom to the required modulus/ align the file offset and the
231 // memory offset seperately this is required so that BSS symbols are handled
232 // properly as the BSS symbols only occupy memory size and not file size
233 uint64_t fOffset = alignOffset(this->fileSize(), atomAlign);
234 uint64_t mOffset = alignOffset(this->memSize(), atomAlign);
235 switch (atomType) {
236 case Atom::definitionRegular:
237 switch(definedAtom->contentType()) {
238 case DefinedAtom::typeCode:
239 case DefinedAtom::typeData:
240 case DefinedAtom::typeConstant:
Michael J. Spencer289dced2013-01-29 16:38:03 +0000241 case DefinedAtom::typeGOT:
242 case DefinedAtom::typeStub:
243 case DefinedAtom::typeResolver:
Michael J. Spencer42606572013-01-30 01:25:06 +0000244 _atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0));
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000245 this->_fsize = fOffset + definedAtom->size();
246 this->_msize = mOffset + definedAtom->size();
Michael J. Spencer289dced2013-01-29 16:38:03 +0000247 DEBUG_WITH_TYPE("Section",
248 llvm::dbgs() << "[" << this->name() << " " << this << "] "
249 << "Adding atom: " << atom->name() << "@"
250 << fOffset << "\n");
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000251 break;
252 case DefinedAtom::typeZeroFill:
Michael J. Spencer42606572013-01-30 01:25:06 +0000253 _atoms.push_back(new (_alloc) AtomLayout(atom, mOffset, 0));
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000254 this->_msize = mOffset + definedAtom->size();
255 break;
256 default:
Michael J. Spencer42606572013-01-30 01:25:06 +0000257 llvm::dbgs() << definedAtom->contentType() << "\n";
258 llvm_unreachable("Uexpected content type.");
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000259 }
260 break;
261 default:
262 llvm_unreachable("Expecting only definedAtoms being passed here");
263 break;
264 }
265 // Set the section alignment to the largest alignment
266 // std::max doesnot support uint64_t
267 if (this->_align2 < align2)
268 this->_align2 = align2;
Michael J. Spencer42606572013-01-30 01:25:06 +0000269
270 return *_atoms.back();
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000271}
272
273/// \brief Get the section flags, defined by the permissions of the section
274template<class ELFT>
275int64_t
276Section<ELFT>::flags() {
277 switch (_contentPermissions) {
278 case DefinedAtom::perm___:
279 return 0;
280
281 case DefinedAtom::permR__:
282 return llvm::ELF::SHF_ALLOC;
283
284 case DefinedAtom::permR_X:
285 return llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR;
286
287 case DefinedAtom::permRW_:
288 case DefinedAtom::permRW_L:
289 return llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE;
290
291 case DefinedAtom::permRWX:
292 return llvm::ELF::SHF_ALLOC |
293 llvm::ELF::SHF_WRITE |
294 llvm::ELF::SHF_EXECINSTR;
295
296 default:
297 break;
298 }
299 return llvm::ELF::SHF_ALLOC;
300}
301
302/// \brief Return the section type, the returned value is recorded in the
303/// sh_type field of the Section Header
304
305template<class ELFT>
306int
307Section<ELFT>::type() {
Michael J. Spencer289dced2013-01-29 16:38:03 +0000308 if (_sectionKind == K_SymbolTable)
309 return llvm::ELF::SHT_SYMTAB;
310
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000311 switch (_contentType) {
312 case DefinedAtom::typeCode:
313 case DefinedAtom::typeData:
314 case DefinedAtom::typeConstant:
Michael J. Spencer289dced2013-01-29 16:38:03 +0000315 case DefinedAtom::typeGOT:
316 case DefinedAtom::typeStub:
317 case DefinedAtom::typeResolver:
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000318 return llvm::ELF::SHT_PROGBITS;
319
320 case DefinedAtom::typeZeroFill:
321 return llvm::ELF::SHT_NOBITS;
322
323 // Case to handle section types
324 // Symtab, String Table ...
325 default:
326 return _contentType;
327 }
328}
329
330/// \brief convert the segment type to a String for diagnostics
331/// and printing purposes
332template<class ELFT>
333StringRef
334Section<ELFT>::segmentKindToStr() const {
335 switch(_segmentType) {
336 case llvm::ELF::PT_INTERP:
337 return "INTERP";
338 case llvm::ELF::PT_LOAD:
339 return "LOAD";
340 case llvm::ELF::PT_GNU_EH_FRAME:
341 return "EH_FRAME";
342 case llvm::ELF::PT_NOTE:
343 return "NOTE";
344 case llvm::ELF::PT_DYNAMIC:
345 return "DYNAMIC";
346 case llvm::ELF::PT_GNU_RELRO:
347 return "RELRO";
348 case llvm::ELF::PT_NULL:
349 return "NULL";
350 default:
351 return "UNKNOWN";
352 }
353}
354
355/// \brief Write the section and the atom contents to the buffer
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000356template <class ELFT>
357void Section<ELFT>::write(ELFWriter *writer, llvm::FileOutputBuffer &buffer) {
358 uint8_t *chunkBuffer = buffer.getBufferStart();
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000359 for (auto &ai : _atoms) {
Michael J. Spencer289dced2013-01-29 16:38:03 +0000360 DEBUG_WITH_TYPE("Section",
Michael J. Spencer42606572013-01-30 01:25:06 +0000361 llvm::dbgs() << "Writing atom: " << ai->_atom->name()
362 << " | " << ai->_fileOffset << "\n");
363 const DefinedAtom *definedAtom = cast<DefinedAtom>(ai->_atom);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000364 if (definedAtom->contentType() == DefinedAtom::typeZeroFill)
365 continue;
366 // Copy raw content of atom to file buffer.
367 llvm::ArrayRef<uint8_t> content = definedAtom->rawContent();
368 uint64_t contentSize = content.size();
369 if (contentSize == 0)
370 continue;
Michael J. Spencer42606572013-01-30 01:25:06 +0000371 uint8_t *atomContent = chunkBuffer + ai->_fileOffset;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000372 std::copy_n(content.data(), contentSize, atomContent);
373 for (const auto ref : *definedAtom) {
374 uint32_t offset = ref->offsetInAtom();
375 uint64_t targetAddress = 0;
376 assert(ref->target() != nullptr && "Found the target to be NULL");
377 targetAddress = writer->addressOfAtom(ref->target());
Michael J. Spencer42606572013-01-30 01:25:06 +0000378 uint64_t fixupAddress = writer->addressOfAtom(ai->_atom) + offset;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000379 // apply the relocation
380 writer->kindHandler()->applyFixup(ref->kind(),
381 ref->addend(),
382 &atomContent[offset],
383 fixupAddress,
384 targetAddress);
385 }
386 }
387}
388
389/// \brief A MergedSections represents a set of sections grouped by the same
390/// name. The output file that gets written by the linker has sections grouped
391/// by similiar names
392template<class ELFT>
393class MergedSections {
394public:
395 // Iterators
396 typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter;
397
Michael J. Spencere68f9032013-01-29 22:03:39 +0000398 MergedSections(StringRef name);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000399
400 // Appends a section into the list of sections that are part of this Merged
401 // Section
402 void appendSection(Chunk<ELFT> *c);
403
404 // Set the MergedSections is associated with a segment
405 inline void setHasSegment() { _hasSegment = true; }
406
407 /// Sets the ordinal
408 inline void setOrdinal(uint64_t ordinal) {
409 _ordinal = ordinal;
410 }
411
412 /// Sets the Memory size
413 inline void setMemSize(uint64_t memsz) {
414 _memSize = memsz;
415 }
416
417 /// Sets the size fo the merged Section
418 inline void setSize(uint64_t fsiz) {
419 _size = fsiz;
420 }
421
422 // The offset of the first section contained in the merged section is
423 // contained here
424 inline void setFileOffset(uint64_t foffset) {
425 _fileOffset = foffset;
426 }
427
428 // Sets the starting address of the section
429 inline void setAddr(uint64_t addr) {
430 _virtualAddr = addr;
431 }
432
433 inline range<ChunkIter> sections() { return _sections; }
434
435 // The below functions returns the properties of the MergeSection
436 inline bool hasSegment() const { return _hasSegment; }
437
Michael J. Spencere68f9032013-01-29 22:03:39 +0000438 inline StringRef name() const { return _name; }
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000439
440 inline int64_t shinfo() const { return _shInfo; }
441
442 inline uint64_t align2() const { return _align2; }
443
444 inline int64_t link() const { return _link; }
445
446 inline int64_t type() const { return _type; }
447
448 inline uint64_t virtualAddr() const { return _virtualAddr; }
449
450 inline int64_t ordinal() const { return _ordinal; }
451
452 inline int64_t kind() const { return _kind; }
453
454 inline uint64_t fileSize() const { return _size; }
455
456 inline int64_t entsize() const { return _entSize; }
457
458 inline uint64_t fileOffset() const { return _fileOffset; }
459
460 inline int64_t flags() const { return _flags; }
461
462 inline uint64_t memSize() { return _memSize; }
463
464private:
Michael J. Spencere68f9032013-01-29 22:03:39 +0000465 StringRef _name;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000466 bool _hasSegment;
467 uint64_t _ordinal;
468 int64_t _flags;
469 uint64_t _size;
470 uint64_t _memSize;
471 uint64_t _fileOffset;
472 uint64_t _virtualAddr;
473 int64_t _shInfo;
474 int64_t _entSize;
475 int64_t _link;
476 uint64_t _align2;
477 int64_t _kind;
478 int64_t _type;
479 std::vector<Chunk<ELFT> *> _sections;
480};
481
482/// MergedSections
483template<class ELFT>
484MergedSections<ELFT>::MergedSections(StringRef name)
485 : _name(name)
486 ,_hasSegment(false)
487 ,_ordinal(0)
488 ,_flags(0)
489 ,_size(0)
490 ,_memSize(0)
491 ,_fileOffset(0)
492 ,_virtualAddr(0)
493 ,_shInfo(0)
494 ,_entSize(0)
495 ,_link(0)
496 ,_align2(0)
497 ,_kind(0)
498 ,_type(0) { }
499
500
501template<class ELFT>
502void
503MergedSections<ELFT>::appendSection(Chunk<ELFT> *c) {
504 if (c->align2() > _align2)
505 _align2 = c->align2();
506 if (const auto section = dyn_cast<Section<ELFT>>(c)) {
507 _link = section->link();
508 _shInfo = section->shinfo();
509 _entSize = section->entsize();
510 _type = section->type();
511 if (_flags < section->flags())
512 _flags = section->flags();
513 }
514 _kind = c->kind();
515 _sections.push_back(c);
516}
517
518/// \brief The class represents the ELF String Table
519template<class ELFT>
Michael J. Spencere68f9032013-01-29 22:03:39 +0000520class StringTable : public Section<ELFT> {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000521public:
Michael J. Spencere68f9032013-01-29 22:03:39 +0000522 StringTable(const ELFTargetInfo &, const char *str, int32_t order);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000523
524 static inline bool classof(const Chunk<ELFT> *c) {
525 return c->kind() == Section<ELFT>::K_StringTable;
526 }
527
Shankar Easwarana6f00fe2013-01-30 07:11:43 +0000528 uint64_t addString(StringRef symname);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000529
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000530 void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000531
532 inline void finalize() { }
533
534private:
Michael J. Spencere68f9032013-01-29 22:03:39 +0000535 std::vector<StringRef> _strings;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000536};
537
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000538template <class ELFT>
Michael J. Spencere68f9032013-01-29 22:03:39 +0000539StringTable<ELFT>::StringTable(const ELFTargetInfo &ti, const char *str,
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000540 int32_t order)
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000541 : Section<ELFT>(ti, str, llvm::ELF::SHT_STRTAB, DefinedAtom::perm___, order,
542 Section<ELFT>::K_StringTable) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000543 // the string table has a NULL entry for which
544 // add an empty string
545 _strings.push_back("");
546 this->_fsize = 1;
547 this->_align2 = 1;
548 this->setOrder(order);
549}
550
Shankar Easwarana6f00fe2013-01-30 07:11:43 +0000551template <class ELFT> uint64_t StringTable<ELFT>::addString(StringRef symname) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000552 _strings.push_back(symname);
553 uint64_t offset = this->_fsize;
554 this->_fsize += symname.size() + 1;
555 return offset;
556}
557
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000558template <class ELFT>
Michael J. Spencere68f9032013-01-29 22:03:39 +0000559void StringTable<ELFT>::write(ELFWriter *writer,
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000560 llvm::FileOutputBuffer &buffer) {
561 uint8_t *chunkBuffer = buffer.getBufferStart();
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000562 uint8_t *dest = chunkBuffer + this->fileOffset();
563 for (auto si : _strings) {
564 memcpy(dest, si.data(), si.size());
565 dest += si.size();
566 memcpy(dest, "", 1);
567 dest += 1;
568 }
569}
570
Michael J. Spencere68f9032013-01-29 22:03:39 +0000571/// \brief The SymbolTable class represents the symbol table in a ELF file
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000572template<class ELFT>
Michael J. Spencere68f9032013-01-29 22:03:39 +0000573class SymbolTable : public Section<ELFT> {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000574public:
575 typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
576
Michael J. Spencere68f9032013-01-29 22:03:39 +0000577 SymbolTable(const ELFTargetInfo &ti, const char *str, int32_t order);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000578
579 void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0);
580
581 void finalize();
582
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000583 void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000584
585 static inline bool classof(const Chunk<ELFT> *c) {
586 return c->kind() == Section<ELFT>::K_SymbolTable;
587 }
588
Michael J. Spencere68f9032013-01-29 22:03:39 +0000589 inline void setStringSection(StringTable<ELFT> *s) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000590 _stringSection = s;
591 }
592
593private:
Michael J. Spencere68f9032013-01-29 22:03:39 +0000594 StringTable<ELFT> *_stringSection;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000595 std::vector<Elf_Sym*> _symbolTable;
596 llvm::BumpPtrAllocator _symbolAllocate;
597 int64_t _link;
598};
599
600/// ELF Symbol Table
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000601template <class ELFT>
Michael J. Spencere68f9032013-01-29 22:03:39 +0000602SymbolTable<ELFT>::SymbolTable(const ELFTargetInfo &ti, const char *str,
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000603 int32_t order)
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000604 : Section<ELFT>(ti, str, llvm::ELF::SHT_SYMTAB, 0, order,
605 Section<ELFT>::K_SymbolTable) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000606 this->setOrder(order);
607 Elf_Sym *symbol = new (_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
608 memset((void *)symbol, 0, sizeof(Elf_Sym));
609 _symbolTable.push_back(symbol);
610 this->_entSize = sizeof(Elf_Sym);
611 this->_fsize = sizeof(Elf_Sym);
612 this->_align2 = sizeof(void *);
613}
614
615template<class ELFT>
616void
Michael J. Spencere68f9032013-01-29 22:03:39 +0000617SymbolTable<ELFT>::addSymbol(const Atom *atom,
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000618 int32_t sectionIndex,
619 uint64_t addr) {
620 Elf_Sym *symbol = new(_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
621 unsigned char binding = 0, type = 0;
622 symbol->st_name = _stringSection->addString(atom->name());
623 symbol->st_size = 0;
624 symbol->st_shndx = sectionIndex;
625 symbol->st_value = 0;
626 symbol->st_other = llvm::ELF::STV_DEFAULT;
627 if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom)){
628 symbol->st_size = da->size();
Michael J. Spencere68f9032013-01-29 22:03:39 +0000629 DefinedAtom::ContentType ct;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000630 switch (ct = da->contentType()){
Michael J. Spencere68f9032013-01-29 22:03:39 +0000631 case DefinedAtom::typeCode:
Michael J. Spencer289dced2013-01-29 16:38:03 +0000632 case DefinedAtom::typeStub:
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000633 symbol->st_value = addr;
634 type = llvm::ELF::STT_FUNC;
635 break;
Michael J. Spencer289dced2013-01-29 16:38:03 +0000636 case DefinedAtom::typeResolver:
637 symbol->st_value = addr;
638 type = llvm::ELF::STT_GNU_IFUNC;
639 break;
Michael J. Spencere68f9032013-01-29 22:03:39 +0000640 case DefinedAtom::typeData:
641 case DefinedAtom::typeConstant:
Michael J. Spencer289dced2013-01-29 16:38:03 +0000642 case DefinedAtom::typeGOT:
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000643 symbol->st_value = addr;
644 type = llvm::ELF::STT_OBJECT;
645 break;
Michael J. Spencere68f9032013-01-29 22:03:39 +0000646 case DefinedAtom::typeZeroFill:
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000647 type = llvm::ELF::STT_OBJECT;
648 symbol->st_value = addr;
649 break;
650 default:
651 type = llvm::ELF::STT_NOTYPE;
652 }
653 if (da->scope() == DefinedAtom::scopeTranslationUnit)
654 binding = llvm::ELF::STB_LOCAL;
655 else
656 binding = llvm::ELF::STB_GLOBAL;
657 } else if (const AbsoluteAtom *aa = dyn_cast<const AbsoluteAtom>(atom)){
658 type = llvm::ELF::STT_OBJECT;
659 symbol->st_shndx = llvm::ELF::SHN_ABS;
660 switch (aa->scope()) {
661 case AbsoluteAtom::scopeLinkageUnit:
662 symbol->st_other = llvm::ELF::STV_HIDDEN;
663 binding = llvm::ELF::STB_LOCAL;
664 break;
665 case AbsoluteAtom::scopeTranslationUnit:
666 binding = llvm::ELF::STB_LOCAL;
667 break;
668 case AbsoluteAtom::scopeGlobal:
669 binding = llvm::ELF::STB_GLOBAL;
670 break;
671 }
672 symbol->st_value = addr;
673 } else {
674 symbol->st_value = 0;
675 type = llvm::ELF::STT_NOTYPE;
676 binding = llvm::ELF::STB_WEAK;
677 }
678 symbol->setBindingAndType(binding, type);
679 _symbolTable.push_back(symbol);
680 this->_fsize += sizeof(Elf_Sym);
681}
682
683template<class ELFT>
684void
Michael J. Spencere68f9032013-01-29 22:03:39 +0000685SymbolTable<ELFT>::finalize() {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000686 // sh_info should be one greater than last symbol with STB_LOCAL binding
687 // we sort the symbol table to keep all local symbols at the beginning
688 std::stable_sort(_symbolTable.begin(), _symbolTable.end(),
689 [](const Elf_Sym *A, const Elf_Sym *B) {
690 return A->getBinding() < B->getBinding();
691 });
692 uint16_t shInfo = 0;
693 for (auto i : _symbolTable) {
694 if (i->getBinding() != llvm::ELF::STB_LOCAL)
695 break;
696 shInfo++;
697 }
698 this->_shInfo = shInfo;
699 this->setLink(_stringSection->ordinal());
700}
701
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000702template <class ELFT>
Michael J. Spencere68f9032013-01-29 22:03:39 +0000703void SymbolTable<ELFT>::write(ELFWriter *writer,
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000704 llvm::FileOutputBuffer &buffer) {
705 uint8_t *chunkBuffer = buffer.getBufferStart();
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000706 uint8_t *dest = chunkBuffer + this->fileOffset();
707 for (auto sti : _symbolTable) {
708 memcpy(dest, sti, sizeof(Elf_Sym));
709 dest += sizeof(Elf_Sym);
710 }
711}
712
Michael J. Spencere68f9032013-01-29 22:03:39 +0000713template <class ELFT> class RelocationTable : public Section<ELFT> {
Michael J. Spencer289dced2013-01-29 16:38:03 +0000714public:
715 typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
716
Michael J. Spencere68f9032013-01-29 22:03:39 +0000717 RelocationTable(const ELFTargetInfo &ti, StringRef str, int32_t order)
Michael J. Spencer289dced2013-01-29 16:38:03 +0000718 : Section<ELFT>(ti, str, llvm::ELF::SHT_RELA, DefinedAtom::permR__, order,
719 Section<ELFT>::K_Default) {
720 this->setOrder(order);
721 this->_entSize = sizeof(Elf_Rela);
722 this->_align2 = llvm::alignOf<Elf_Rela>();
723 }
724
725 void addRelocation(const DefinedAtom &da, const Reference &r) {
726 _relocs.emplace_back(da, r);
727 this->_fsize = _relocs.size() * sizeof(Elf_Rela);
728 this->_msize = this->_fsize;
729 }
730
731 void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer) {
732 uint8_t *chunkBuffer = buffer.getBufferStart();
733 uint8_t *dest = chunkBuffer + this->fileOffset();
734 for (const auto &rel : _relocs) {
735 Elf_Rela *r = reinterpret_cast<Elf_Rela *>(dest);
736 r->setSymbolAndType(0, rel.second.kind());
737 r->r_offset =
738 writer->addressOfAtom(&rel.first) + rel.second.offsetInAtom();
739 r->r_addend =
740 writer->addressOfAtom(rel.second.target()) + rel.second.addend();
741 dest += sizeof(Elf_Rela);
742 DEBUG_WITH_TYPE("ELFRelocationTable", llvm::dbgs()
743 << "IRELATIVE relocation at " << rel.first.name() << "@"
744 << r->r_offset << " to " << rel.second.target()->name()
745 << "@" << r->r_addend << "\n");
746 }
747 }
748
749private:
750 std::vector<std::pair<const DefinedAtom &, const Reference &>> _relocs;
751};
Michael J. Spencere68f9032013-01-29 22:03:39 +0000752} // end namespace elf
753} // end namespace lld
Michael J. Spencer289dced2013-01-29 16:38:03 +0000754
Michael J. Spencere68f9032013-01-29 22:03:39 +0000755#endif