blob: ffb38c5374072e83d137e15671186f7b600f4cfb [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
Michael J. Spencere68f9032013-01-29 22:03:39 +000048 Section(const ELFTargetInfo &, const 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
57 /// Align the offset to the required modulus defined by the atom alignment
58 uint64_t alignOffset(uint64_t offset, DefinedAtom::Alignment &atomAlign);
59
60 // \brief Append an atom to a Section. The atom gets pushed into a vector
61 // contains the atom, the atom file offset, the atom virtual address
62 // the atom file offset is aligned appropriately as set by the Reader
63 void appendAtom(const Atom *atom);
64
65 /// \brief Set the virtual address of each Atom in the Section. This
66 /// routine gets called after the linker fixes up the virtual address
67 /// of the section
68 inline void assignVirtualAddress(uint64_t &addr) {
69 for (auto &ai : _atoms) {
70 ai._virtualAddr = addr + ai._fileOffset;
71 }
72 addr += this->memSize();
73 }
74
75 /// \brief Set the file offset of each Atom in the section. This routine
76 /// gets called after the linker fixes up the section offset
77 inline void assignOffsets(uint64_t offset) {
78 for (auto &ai : _atoms) {
79 ai._fileOffset = offset + ai._fileOffset;
80 }
81 }
82
83 /// \brief Find the Atom address given a name, this is needed to to properly
84 /// apply relocation. The section class calls this to find the atom address
85 /// to fix the relocation
Michael J. Spencere68f9032013-01-29 22:03:39 +000086 inline bool findAtomAddrByName(const StringRef name, uint64_t &addr) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +000087 for (auto ai : _atoms) {
88 if (ai._atom->name() == name) {
89 addr = ai._virtualAddr;
90 return true;
91 }
92 }
93 return false;
94 }
95
96 /// \brief Does the Atom occupy any disk space
97 inline bool occupiesNoDiskSpace() const {
98 return _contentType == DefinedAtom::typeZeroFill;
99 }
100
101 /// \brief The permission of the section is the most permissive permission
102 /// of all atoms that the section contains
103 inline void setContentPermissions(int32_t perm) {
104 _contentPermissions = std::max(perm, _contentPermissions);
105 }
106
107 /// \brief Get the section flags, defined by the permissions of the section
108 int64_t flags();
109
110 /// \brief Return the section type, the returned value is recorded in the
111 /// sh_type field of the Section Header
112 int type();
113
114 /// \brief convert the segment type to a String for diagnostics
115 /// and printing purposes
Michael J. Spencere68f9032013-01-29 22:03:39 +0000116 StringRef segmentKindToStr() const;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000117
118 /// \brief Return the raw flags, we need this to sort segments
119 inline int64_t atomflags() const {
120 return _contentPermissions;
121 }
122
123 /// \brief Returns the section link field, the returned value is
124 /// recorded in the sh_link field of the Section Header
125 inline int link() const {
126 return _link;
127 }
128
129 inline void setLink(int32_t link) {
130 _link = link;
131 }
132
133 /// \brief Returns the section entsize field, the returned value is
134 /// recorded in the sh_entsize field of the Section Header
135 inline int entsize() const {
136 return _entSize;
137 }
138
139 /// \brief Returns the shinfo field, the returned value is
140 /// recorded in the sh_info field of the Section Header
141 inline int shinfo() const {
142 return _shInfo;
143 }
144
145 /// \brief Records the segmentType, that this section belongs to
Michael J. Spencere68f9032013-01-29 22:03:39 +0000146 inline void setSegment(const Layout::SegmentType segmentType) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000147 _segmentType = segmentType;
148 }
149
150 /// \brief for LLVM style RTTI information
151 static inline bool classof(const Chunk<ELFT> *c) {
152 return c->kind() == Chunk<ELFT>::K_ELFSection;
153 }
154
155 /// \brief Finalize the section contents before writing
156 inline void finalize() { }
157
158 /// \brief Write the section and the atom contents to the buffer
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000159 void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000160
161 /// Atom Iterators
162 typedef typename std::vector<AtomLayout>::iterator atom_iter;
163
164 range<atom_iter> atoms() { return _atoms; }
165
166protected:
167 int32_t _contentType;
168 int32_t _contentPermissions;
169 SectionKind _sectionKind;
170 std::vector<AtomLayout> _atoms;
Michael J. Spencere68f9032013-01-29 22:03:39 +0000171 Layout::SegmentType _segmentType;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000172 int64_t _entSize;
173 int64_t _shInfo;
174 int64_t _link;
175};
176
177// Create a section object, the section is set to the default type if the
178// caller doesnot set it
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000179template <class ELFT>
180Section<ELFT>::Section(const ELFTargetInfo &ti, const StringRef sectionName,
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000181 const int32_t contentType,
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000182 const int32_t contentPermissions, const int32_t order,
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000183 const SectionKind kind)
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000184 : Chunk<ELFT>(sectionName, Chunk<ELFT>::K_ELFSection, ti),
185 _contentType(contentType), _contentPermissions(contentPermissions),
186 _sectionKind(kind), _entSize(0), _shInfo(0), _link(0) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000187 this->setOrder(order);
188}
189
190/// Align the offset to the required modulus defined by the atom alignment
191template<class ELFT>
192uint64_t
193Section<ELFT>::alignOffset(uint64_t offset, DefinedAtom::Alignment &atomAlign) {
194 uint64_t requiredModulus = atomAlign.modulus;
195 uint64_t align2 = 1u << atomAlign.powerOf2;
196 uint64_t currentModulus = (offset % align2);
197 uint64_t retOffset = offset;
198 if (currentModulus != requiredModulus) {
199 if (requiredModulus > currentModulus)
200 retOffset += requiredModulus - currentModulus;
201 else
202 retOffset += align2 + requiredModulus - currentModulus;
203 }
204 return retOffset;
205}
206
207// \brief Append an atom to a Section. The atom gets pushed into a vector
208// contains the atom, the atom file offset, the atom virtual address
209// the atom file offset is aligned appropriately as set by the Reader
210template<class ELFT>
211void
212Section<ELFT>::appendAtom(const Atom *atom) {
213 Atom::Definition atomType = atom->definition();
214 const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
215
216 DefinedAtom::Alignment atomAlign = definedAtom->alignment();
217 uint64_t align2 = 1u << atomAlign.powerOf2;
218 // Align the atom to the required modulus/ align the file offset and the
219 // memory offset seperately this is required so that BSS symbols are handled
220 // properly as the BSS symbols only occupy memory size and not file size
221 uint64_t fOffset = alignOffset(this->fileSize(), atomAlign);
222 uint64_t mOffset = alignOffset(this->memSize(), atomAlign);
223 switch (atomType) {
224 case Atom::definitionRegular:
225 switch(definedAtom->contentType()) {
226 case DefinedAtom::typeCode:
227 case DefinedAtom::typeData:
228 case DefinedAtom::typeConstant:
Michael J. Spencer289dced2013-01-29 16:38:03 +0000229 case DefinedAtom::typeGOT:
230 case DefinedAtom::typeStub:
231 case DefinedAtom::typeResolver:
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000232 _atoms.push_back(AtomLayout(atom, fOffset, 0));
233 this->_fsize = fOffset + definedAtom->size();
234 this->_msize = mOffset + definedAtom->size();
Michael J. Spencer289dced2013-01-29 16:38:03 +0000235 DEBUG_WITH_TYPE("Section",
236 llvm::dbgs() << "[" << this->name() << " " << this << "] "
237 << "Adding atom: " << atom->name() << "@"
238 << fOffset << "\n");
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000239 break;
240 case DefinedAtom::typeZeroFill:
241 _atoms.push_back(AtomLayout(atom, mOffset, 0));
242 this->_msize = mOffset + definedAtom->size();
243 break;
244 default:
245 this->_fsize = fOffset + definedAtom->size();
246 this->_msize = mOffset + definedAtom->size();
247 break;
248 }
249 break;
250 default:
251 llvm_unreachable("Expecting only definedAtoms being passed here");
252 break;
253 }
254 // Set the section alignment to the largest alignment
255 // std::max doesnot support uint64_t
256 if (this->_align2 < align2)
257 this->_align2 = align2;
258}
259
260/// \brief Get the section flags, defined by the permissions of the section
261template<class ELFT>
262int64_t
263Section<ELFT>::flags() {
264 switch (_contentPermissions) {
265 case DefinedAtom::perm___:
266 return 0;
267
268 case DefinedAtom::permR__:
269 return llvm::ELF::SHF_ALLOC;
270
271 case DefinedAtom::permR_X:
272 return llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR;
273
274 case DefinedAtom::permRW_:
275 case DefinedAtom::permRW_L:
276 return llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE;
277
278 case DefinedAtom::permRWX:
279 return llvm::ELF::SHF_ALLOC |
280 llvm::ELF::SHF_WRITE |
281 llvm::ELF::SHF_EXECINSTR;
282
283 default:
284 break;
285 }
286 return llvm::ELF::SHF_ALLOC;
287}
288
289/// \brief Return the section type, the returned value is recorded in the
290/// sh_type field of the Section Header
291
292template<class ELFT>
293int
294Section<ELFT>::type() {
Michael J. Spencer289dced2013-01-29 16:38:03 +0000295 if (_sectionKind == K_SymbolTable)
296 return llvm::ELF::SHT_SYMTAB;
297
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000298 switch (_contentType) {
299 case DefinedAtom::typeCode:
300 case DefinedAtom::typeData:
301 case DefinedAtom::typeConstant:
Michael J. Spencer289dced2013-01-29 16:38:03 +0000302 case DefinedAtom::typeGOT:
303 case DefinedAtom::typeStub:
304 case DefinedAtom::typeResolver:
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000305 return llvm::ELF::SHT_PROGBITS;
306
307 case DefinedAtom::typeZeroFill:
308 return llvm::ELF::SHT_NOBITS;
309
310 // Case to handle section types
311 // Symtab, String Table ...
312 default:
313 return _contentType;
314 }
315}
316
317/// \brief convert the segment type to a String for diagnostics
318/// and printing purposes
319template<class ELFT>
320StringRef
321Section<ELFT>::segmentKindToStr() const {
322 switch(_segmentType) {
323 case llvm::ELF::PT_INTERP:
324 return "INTERP";
325 case llvm::ELF::PT_LOAD:
326 return "LOAD";
327 case llvm::ELF::PT_GNU_EH_FRAME:
328 return "EH_FRAME";
329 case llvm::ELF::PT_NOTE:
330 return "NOTE";
331 case llvm::ELF::PT_DYNAMIC:
332 return "DYNAMIC";
333 case llvm::ELF::PT_GNU_RELRO:
334 return "RELRO";
335 case llvm::ELF::PT_NULL:
336 return "NULL";
337 default:
338 return "UNKNOWN";
339 }
340}
341
342/// \brief Write the section and the atom contents to the buffer
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000343template <class ELFT>
344void Section<ELFT>::write(ELFWriter *writer, llvm::FileOutputBuffer &buffer) {
345 uint8_t *chunkBuffer = buffer.getBufferStart();
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000346 for (auto &ai : _atoms) {
Michael J. Spencer289dced2013-01-29 16:38:03 +0000347 DEBUG_WITH_TYPE("Section",
348 llvm::dbgs() << "Writing atom: " << ai._atom->name()
349 << " | " << ai._fileOffset << "\n");
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000350 const DefinedAtom *definedAtom = cast<DefinedAtom>(ai._atom);
351 if (definedAtom->contentType() == DefinedAtom::typeZeroFill)
352 continue;
353 // Copy raw content of atom to file buffer.
354 llvm::ArrayRef<uint8_t> content = definedAtom->rawContent();
355 uint64_t contentSize = content.size();
356 if (contentSize == 0)
357 continue;
358 uint8_t *atomContent = chunkBuffer + ai._fileOffset;
359 std::copy_n(content.data(), contentSize, atomContent);
360 for (const auto ref : *definedAtom) {
361 uint32_t offset = ref->offsetInAtom();
362 uint64_t targetAddress = 0;
363 assert(ref->target() != nullptr && "Found the target to be NULL");
364 targetAddress = writer->addressOfAtom(ref->target());
365 uint64_t fixupAddress = writer->addressOfAtom(ai._atom) + offset;
366 // apply the relocation
367 writer->kindHandler()->applyFixup(ref->kind(),
368 ref->addend(),
369 &atomContent[offset],
370 fixupAddress,
371 targetAddress);
372 }
373 }
374}
375
376/// \brief A MergedSections represents a set of sections grouped by the same
377/// name. The output file that gets written by the linker has sections grouped
378/// by similiar names
379template<class ELFT>
380class MergedSections {
381public:
382 // Iterators
383 typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter;
384
Michael J. Spencere68f9032013-01-29 22:03:39 +0000385 MergedSections(StringRef name);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000386
387 // Appends a section into the list of sections that are part of this Merged
388 // Section
389 void appendSection(Chunk<ELFT> *c);
390
391 // Set the MergedSections is associated with a segment
392 inline void setHasSegment() { _hasSegment = true; }
393
394 /// Sets the ordinal
395 inline void setOrdinal(uint64_t ordinal) {
396 _ordinal = ordinal;
397 }
398
399 /// Sets the Memory size
400 inline void setMemSize(uint64_t memsz) {
401 _memSize = memsz;
402 }
403
404 /// Sets the size fo the merged Section
405 inline void setSize(uint64_t fsiz) {
406 _size = fsiz;
407 }
408
409 // The offset of the first section contained in the merged section is
410 // contained here
411 inline void setFileOffset(uint64_t foffset) {
412 _fileOffset = foffset;
413 }
414
415 // Sets the starting address of the section
416 inline void setAddr(uint64_t addr) {
417 _virtualAddr = addr;
418 }
419
420 inline range<ChunkIter> sections() { return _sections; }
421
422 // The below functions returns the properties of the MergeSection
423 inline bool hasSegment() const { return _hasSegment; }
424
Michael J. Spencere68f9032013-01-29 22:03:39 +0000425 inline StringRef name() const { return _name; }
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000426
427 inline int64_t shinfo() const { return _shInfo; }
428
429 inline uint64_t align2() const { return _align2; }
430
431 inline int64_t link() const { return _link; }
432
433 inline int64_t type() const { return _type; }
434
435 inline uint64_t virtualAddr() const { return _virtualAddr; }
436
437 inline int64_t ordinal() const { return _ordinal; }
438
439 inline int64_t kind() const { return _kind; }
440
441 inline uint64_t fileSize() const { return _size; }
442
443 inline int64_t entsize() const { return _entSize; }
444
445 inline uint64_t fileOffset() const { return _fileOffset; }
446
447 inline int64_t flags() const { return _flags; }
448
449 inline uint64_t memSize() { return _memSize; }
450
451private:
Michael J. Spencere68f9032013-01-29 22:03:39 +0000452 StringRef _name;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000453 bool _hasSegment;
454 uint64_t _ordinal;
455 int64_t _flags;
456 uint64_t _size;
457 uint64_t _memSize;
458 uint64_t _fileOffset;
459 uint64_t _virtualAddr;
460 int64_t _shInfo;
461 int64_t _entSize;
462 int64_t _link;
463 uint64_t _align2;
464 int64_t _kind;
465 int64_t _type;
466 std::vector<Chunk<ELFT> *> _sections;
467};
468
469/// MergedSections
470template<class ELFT>
471MergedSections<ELFT>::MergedSections(StringRef name)
472 : _name(name)
473 ,_hasSegment(false)
474 ,_ordinal(0)
475 ,_flags(0)
476 ,_size(0)
477 ,_memSize(0)
478 ,_fileOffset(0)
479 ,_virtualAddr(0)
480 ,_shInfo(0)
481 ,_entSize(0)
482 ,_link(0)
483 ,_align2(0)
484 ,_kind(0)
485 ,_type(0) { }
486
487
488template<class ELFT>
489void
490MergedSections<ELFT>::appendSection(Chunk<ELFT> *c) {
491 if (c->align2() > _align2)
492 _align2 = c->align2();
493 if (const auto section = dyn_cast<Section<ELFT>>(c)) {
494 _link = section->link();
495 _shInfo = section->shinfo();
496 _entSize = section->entsize();
497 _type = section->type();
498 if (_flags < section->flags())
499 _flags = section->flags();
500 }
501 _kind = c->kind();
502 _sections.push_back(c);
503}
504
505/// \brief The class represents the ELF String Table
506template<class ELFT>
Michael J. Spencere68f9032013-01-29 22:03:39 +0000507class StringTable : public Section<ELFT> {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000508public:
Michael J. Spencere68f9032013-01-29 22:03:39 +0000509 StringTable(const ELFTargetInfo &, const char *str, int32_t order);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000510
511 static inline bool classof(const Chunk<ELFT> *c) {
512 return c->kind() == Section<ELFT>::K_StringTable;
513 }
514
Michael J. Spencere68f9032013-01-29 22:03:39 +0000515 uint64_t addString(const StringRef symname);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000516
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000517 void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000518
519 inline void finalize() { }
520
521private:
Michael J. Spencere68f9032013-01-29 22:03:39 +0000522 std::vector<StringRef> _strings;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000523};
524
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000525template <class ELFT>
Michael J. Spencere68f9032013-01-29 22:03:39 +0000526StringTable<ELFT>::StringTable(const ELFTargetInfo &ti, const char *str,
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000527 int32_t order)
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000528 : Section<ELFT>(ti, str, llvm::ELF::SHT_STRTAB, DefinedAtom::perm___, order,
529 Section<ELFT>::K_StringTable) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000530 // the string table has a NULL entry for which
531 // add an empty string
532 _strings.push_back("");
533 this->_fsize = 1;
534 this->_align2 = 1;
535 this->setOrder(order);
536}
537
538template<class ELFT>
539uint64_t
Michael J. Spencere68f9032013-01-29 22:03:39 +0000540StringTable<ELFT>::addString(const StringRef symname) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000541 _strings.push_back(symname);
542 uint64_t offset = this->_fsize;
543 this->_fsize += symname.size() + 1;
544 return offset;
545}
546
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000547template <class ELFT>
Michael J. Spencere68f9032013-01-29 22:03:39 +0000548void StringTable<ELFT>::write(ELFWriter *writer,
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000549 llvm::FileOutputBuffer &buffer) {
550 uint8_t *chunkBuffer = buffer.getBufferStart();
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000551 uint8_t *dest = chunkBuffer + this->fileOffset();
552 for (auto si : _strings) {
553 memcpy(dest, si.data(), si.size());
554 dest += si.size();
555 memcpy(dest, "", 1);
556 dest += 1;
557 }
558}
559
Michael J. Spencere68f9032013-01-29 22:03:39 +0000560/// \brief The SymbolTable class represents the symbol table in a ELF file
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000561template<class ELFT>
Michael J. Spencere68f9032013-01-29 22:03:39 +0000562class SymbolTable : public Section<ELFT> {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000563public:
564 typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
565
Michael J. Spencere68f9032013-01-29 22:03:39 +0000566 SymbolTable(const ELFTargetInfo &ti, const char *str, int32_t order);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000567
568 void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0);
569
570 void finalize();
571
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000572 void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer);
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000573
574 static inline bool classof(const Chunk<ELFT> *c) {
575 return c->kind() == Section<ELFT>::K_SymbolTable;
576 }
577
Michael J. Spencere68f9032013-01-29 22:03:39 +0000578 inline void setStringSection(StringTable<ELFT> *s) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000579 _stringSection = s;
580 }
581
582private:
Michael J. Spencere68f9032013-01-29 22:03:39 +0000583 StringTable<ELFT> *_stringSection;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000584 std::vector<Elf_Sym*> _symbolTable;
585 llvm::BumpPtrAllocator _symbolAllocate;
586 int64_t _link;
587};
588
589/// ELF Symbol Table
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000590template <class ELFT>
Michael J. Spencere68f9032013-01-29 22:03:39 +0000591SymbolTable<ELFT>::SymbolTable(const ELFTargetInfo &ti, const char *str,
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000592 int32_t order)
Michael J. Spencerbf77be32013-01-29 01:07:47 +0000593 : Section<ELFT>(ti, str, llvm::ELF::SHT_SYMTAB, 0, order,
594 Section<ELFT>::K_SymbolTable) {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000595 this->setOrder(order);
596 Elf_Sym *symbol = new (_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
597 memset((void *)symbol, 0, sizeof(Elf_Sym));
598 _symbolTable.push_back(symbol);
599 this->_entSize = sizeof(Elf_Sym);
600 this->_fsize = sizeof(Elf_Sym);
601 this->_align2 = sizeof(void *);
602}
603
604template<class ELFT>
605void
Michael J. Spencere68f9032013-01-29 22:03:39 +0000606SymbolTable<ELFT>::addSymbol(const Atom *atom,
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000607 int32_t sectionIndex,
608 uint64_t addr) {
609 Elf_Sym *symbol = new(_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
610 unsigned char binding = 0, type = 0;
611 symbol->st_name = _stringSection->addString(atom->name());
612 symbol->st_size = 0;
613 symbol->st_shndx = sectionIndex;
614 symbol->st_value = 0;
615 symbol->st_other = llvm::ELF::STV_DEFAULT;
616 if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom)){
617 symbol->st_size = da->size();
Michael J. Spencere68f9032013-01-29 22:03:39 +0000618 DefinedAtom::ContentType ct;
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000619 switch (ct = da->contentType()){
Michael J. Spencere68f9032013-01-29 22:03:39 +0000620 case DefinedAtom::typeCode:
Michael J. Spencer289dced2013-01-29 16:38:03 +0000621 case DefinedAtom::typeStub:
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000622 symbol->st_value = addr;
623 type = llvm::ELF::STT_FUNC;
624 break;
Michael J. Spencer289dced2013-01-29 16:38:03 +0000625 case DefinedAtom::typeResolver:
626 symbol->st_value = addr;
627 type = llvm::ELF::STT_GNU_IFUNC;
628 break;
Michael J. Spencere68f9032013-01-29 22:03:39 +0000629 case DefinedAtom::typeData:
630 case DefinedAtom::typeConstant:
Michael J. Spencer289dced2013-01-29 16:38:03 +0000631 case DefinedAtom::typeGOT:
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000632 symbol->st_value = addr;
633 type = llvm::ELF::STT_OBJECT;
634 break;
Michael J. Spencere68f9032013-01-29 22:03:39 +0000635 case DefinedAtom::typeZeroFill:
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000636 type = llvm::ELF::STT_OBJECT;
637 symbol->st_value = addr;
638 break;
639 default:
640 type = llvm::ELF::STT_NOTYPE;
641 }
642 if (da->scope() == DefinedAtom::scopeTranslationUnit)
643 binding = llvm::ELF::STB_LOCAL;
644 else
645 binding = llvm::ELF::STB_GLOBAL;
646 } else if (const AbsoluteAtom *aa = dyn_cast<const AbsoluteAtom>(atom)){
647 type = llvm::ELF::STT_OBJECT;
648 symbol->st_shndx = llvm::ELF::SHN_ABS;
649 switch (aa->scope()) {
650 case AbsoluteAtom::scopeLinkageUnit:
651 symbol->st_other = llvm::ELF::STV_HIDDEN;
652 binding = llvm::ELF::STB_LOCAL;
653 break;
654 case AbsoluteAtom::scopeTranslationUnit:
655 binding = llvm::ELF::STB_LOCAL;
656 break;
657 case AbsoluteAtom::scopeGlobal:
658 binding = llvm::ELF::STB_GLOBAL;
659 break;
660 }
661 symbol->st_value = addr;
662 } else {
663 symbol->st_value = 0;
664 type = llvm::ELF::STT_NOTYPE;
665 binding = llvm::ELF::STB_WEAK;
666 }
667 symbol->setBindingAndType(binding, type);
668 _symbolTable.push_back(symbol);
669 this->_fsize += sizeof(Elf_Sym);
670}
671
672template<class ELFT>
673void
Michael J. Spencere68f9032013-01-29 22:03:39 +0000674SymbolTable<ELFT>::finalize() {
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000675 // sh_info should be one greater than last symbol with STB_LOCAL binding
676 // we sort the symbol table to keep all local symbols at the beginning
677 std::stable_sort(_symbolTable.begin(), _symbolTable.end(),
678 [](const Elf_Sym *A, const Elf_Sym *B) {
679 return A->getBinding() < B->getBinding();
680 });
681 uint16_t shInfo = 0;
682 for (auto i : _symbolTable) {
683 if (i->getBinding() != llvm::ELF::STB_LOCAL)
684 break;
685 shInfo++;
686 }
687 this->_shInfo = shInfo;
688 this->setLink(_stringSection->ordinal());
689}
690
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000691template <class ELFT>
Michael J. Spencere68f9032013-01-29 22:03:39 +0000692void SymbolTable<ELFT>::write(ELFWriter *writer,
Michael J. Spenceradfb7eb2013-01-29 01:00:21 +0000693 llvm::FileOutputBuffer &buffer) {
694 uint8_t *chunkBuffer = buffer.getBufferStart();
Shankar Easwaran6d9921f2013-01-21 20:09:55 +0000695 uint8_t *dest = chunkBuffer + this->fileOffset();
696 for (auto sti : _symbolTable) {
697 memcpy(dest, sti, sizeof(Elf_Sym));
698 dest += sizeof(Elf_Sym);
699 }
700}
701
Michael J. Spencere68f9032013-01-29 22:03:39 +0000702template <class ELFT> class RelocationTable : public Section<ELFT> {
Michael J. Spencer289dced2013-01-29 16:38:03 +0000703public:
704 typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
705
Michael J. Spencere68f9032013-01-29 22:03:39 +0000706 RelocationTable(const ELFTargetInfo &ti, StringRef str, int32_t order)
Michael J. Spencer289dced2013-01-29 16:38:03 +0000707 : Section<ELFT>(ti, str, llvm::ELF::SHT_RELA, DefinedAtom::permR__, order,
708 Section<ELFT>::K_Default) {
709 this->setOrder(order);
710 this->_entSize = sizeof(Elf_Rela);
711 this->_align2 = llvm::alignOf<Elf_Rela>();
712 }
713
714 void addRelocation(const DefinedAtom &da, const Reference &r) {
715 _relocs.emplace_back(da, r);
716 this->_fsize = _relocs.size() * sizeof(Elf_Rela);
717 this->_msize = this->_fsize;
718 }
719
720 void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer) {
721 uint8_t *chunkBuffer = buffer.getBufferStart();
722 uint8_t *dest = chunkBuffer + this->fileOffset();
723 for (const auto &rel : _relocs) {
724 Elf_Rela *r = reinterpret_cast<Elf_Rela *>(dest);
725 r->setSymbolAndType(0, rel.second.kind());
726 r->r_offset =
727 writer->addressOfAtom(&rel.first) + rel.second.offsetInAtom();
728 r->r_addend =
729 writer->addressOfAtom(rel.second.target()) + rel.second.addend();
730 dest += sizeof(Elf_Rela);
731 DEBUG_WITH_TYPE("ELFRelocationTable", llvm::dbgs()
732 << "IRELATIVE relocation at " << rel.first.name() << "@"
733 << r->r_offset << " to " << rel.second.target()->name()
734 << "@" << r->r_addend << "\n");
735 }
736 }
737
738private:
739 std::vector<std::pair<const DefinedAtom &, const Reference &>> _relocs;
740};
Michael J. Spencere68f9032013-01-29 22:03:39 +0000741} // end namespace elf
742} // end namespace lld
Michael J. Spencer289dced2013-01-29 16:38:03 +0000743
Michael J. Spencere68f9032013-01-29 22:03:39 +0000744#endif