aboutsummaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/ELF/HeaderChunks.h
blob: eab132b9b2f697ee512c9fe5f1bdb57cde974e96 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
//===- lib/ReaderWriter/ELF/HeaderChunks.h --------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef LLD_READER_WRITER_ELF_HEADER_CHUNKS_H
#define LLD_READER_WRITER_ELF_HEADER_CHUNKS_H

#include "SegmentChunks.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Format.h"

/// \brief An Header represents the Elf[32/64]_Ehdr structure at the
///        start of an ELF executable file.
namespace lld {
namespace elf {
template <class ELFT> class ELFHeader : public Chunk<ELFT> {
public:
  typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;

  ELFHeader(const ELFLinkingContext &);

  void e_ident(int I, unsigned char C) { _eh.e_ident[I] = C; }
  void e_type(uint16_t type)           { _eh.e_type = type; }
  void e_machine(uint16_t machine)     { _eh.e_machine = machine; }
  void e_version(uint32_t version)     { _eh.e_version = version; }
  void e_entry(int64_t entry)         { _eh.e_entry = entry; }
  void e_phoff(int64_t phoff)         { _eh.e_phoff = phoff; }
  void e_shoff(int64_t shoff)         { _eh.e_shoff = shoff; }
  void e_flags(uint32_t flags)         { _eh.e_flags = flags; }
  void e_ehsize(uint16_t ehsize)       { _eh.e_ehsize = ehsize; }
  void e_phentsize(uint16_t phentsize) { _eh.e_phentsize = phentsize; }
  void e_phnum(uint16_t phnum)         { _eh.e_phnum = phnum; }
  void e_shentsize(uint16_t shentsize) { _eh.e_shentsize = shentsize; }
  void e_shnum(uint16_t shnum)         { _eh.e_shnum = shnum; }
  void e_shstrndx(uint16_t shstrndx)   { _eh.e_shstrndx = shstrndx; }
  uint64_t fileSize() const { return sizeof(Elf_Ehdr); }

  static bool classof(const Chunk<ELFT> *c) {
    return c->Kind() == Chunk<ELFT>::Kind::ELFHeader;
  }

  int getContentType() const { return Chunk<ELFT>::ContentType::Header; }

  void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
             llvm::FileOutputBuffer &buffer);

  virtual void doPreFlight() {}

  void finalize() {
    _eh.e_ident[llvm::ELF::EI_CLASS] =
        (ELFT::Is64Bits) ? llvm::ELF::ELFCLASS64 : llvm::ELF::ELFCLASS32;
    _eh.e_ident[llvm::ELF::EI_DATA] =
        (ELFT::TargetEndianness == llvm::support::little)
            ? llvm::ELF::ELFDATA2LSB
            : llvm::ELF::ELFDATA2MSB;
    _eh.e_type = this->_context.getOutputELFType();
    _eh.e_machine = this->_context.getOutputMachine();
  }

private:
  Elf_Ehdr _eh;
};

template <class ELFT>
ELFHeader<ELFT>::ELFHeader(const ELFLinkingContext &context)
    : Chunk<ELFT>("elfhdr", Chunk<ELFT>::Kind::ELFHeader, context) {
  this->_alignment = ELFT::Is64Bits ? 8 : 4;
  this->_fsize = sizeof(Elf_Ehdr);
  this->_msize = sizeof(Elf_Ehdr);
  memset(_eh.e_ident, 0, llvm::ELF::EI_NIDENT);
  e_ident(llvm::ELF::EI_MAG0, 0x7f);
  e_ident(llvm::ELF::EI_MAG1, 'E');
  e_ident(llvm::ELF::EI_MAG2, 'L');
  e_ident(llvm::ELF::EI_MAG3, 'F');
  e_ehsize(sizeof(Elf_Ehdr));
  e_flags(0);
}

template <class ELFT>
void ELFHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
                            llvm::FileOutputBuffer &buffer) {
  uint8_t *chunkBuffer = buffer.getBufferStart();
  uint8_t *atomContent = chunkBuffer + this->fileOffset();
  memcpy(atomContent, &_eh, fileSize());
}

/// \brief An ProgramHeader represents the Elf[32/64]_Phdr structure at the
///        start of an ELF executable file.
template<class ELFT>
class ProgramHeader : public Chunk<ELFT> {
public:
  typedef llvm::object::Elf_Phdr_Impl<ELFT> Elf_Phdr;
  typedef typename std::vector<Elf_Phdr *>::iterator PhIterT;
  typedef typename std::reverse_iterator<PhIterT> ReversePhIterT;

  /// \brief Find a program header entry, given the type of entry that
  /// we are looking for
  class FindPhdr {
  public:
    FindPhdr(uint64_t type, uint64_t flags, uint64_t flagsClear)
             : _type(type)
             , _flags(flags)
             , _flagsClear(flagsClear) {
    }

    bool operator()(const llvm::object::Elf_Phdr_Impl<ELFT> *j) const {
      return ((j->p_type == _type) &&
              ((j->p_flags & _flags) == _flags) &&
              (!(j->p_flags & _flagsClear)));
    }
  private:
    uint64_t _type;
    uint64_t _flags;
    uint64_t _flagsClear;
  };

  ProgramHeader(const ELFLinkingContext &context)
      : Chunk<ELFT>("elfphdr", Chunk<ELFT>::Kind::ProgramHeader, context) {
    this->_alignment = ELFT::Is64Bits ? 8 : 4;
    resetProgramHeaders();
  }

  bool addSegment(Segment<ELFT> *segment);

  void resetProgramHeaders() { _phi = _ph.begin(); }

  uint64_t fileSize() const { return sizeof(Elf_Phdr) * _ph.size(); }

  static bool classof(const Chunk<ELFT> *c) {
    return c->Kind() == Chunk<ELFT>::Kind::ProgramHeader;
  }

  void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
             llvm::FileOutputBuffer &buffer);

  /// \brief find a program header entry in the list of program headers
  ReversePhIterT
  findProgramHeader(uint64_t type, uint64_t flags, uint64_t flagClear) {
    return std::find_if(_ph.rbegin(), _ph.rend(),
                        FindPhdr(type, flags, flagClear));
  }

  PhIterT begin() {
    return _ph.begin();
  }

  PhIterT end() {
    return _ph.end();
  }

  ReversePhIterT rbegin() { return _ph.rbegin(); }

  ReversePhIterT rend() { return _ph.rend(); }

  virtual void doPreFlight() {}

  void finalize() {}

  int64_t entsize() { return sizeof(Elf_Phdr); }

  int64_t numHeaders() {
    return _ph.size();
  }

  int getContentType() const { return Chunk<ELFT>::ContentType::Header; }

private:
  Elf_Phdr *allocateProgramHeader(bool &allocatedNew) {
    Elf_Phdr *phdr;
    if (_phi == _ph.end()) {
      phdr = new (_allocator) Elf_Phdr;
      _ph.push_back(phdr);
      _phi = _ph.end();
      allocatedNew = true;
    } else {
      phdr = (*_phi);
      ++_phi;
    }
    return phdr;
  }

  std::vector<Elf_Phdr *> _ph;
  PhIterT _phi;
  llvm::BumpPtrAllocator _allocator;
};

template <class ELFT>
bool ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) {
  bool allocatedNew = false;
  ELFLinkingContext::OutputMagic outputMagic = this->_context.getOutputMagic();
  // For segments that are not a loadable segment, we
  // just pick the values directly from the segment as there
  // wouldnt be any slices within that
  if (segment->segmentType() != llvm::ELF::PT_LOAD) {
    Elf_Phdr *phdr = allocateProgramHeader(allocatedNew);
    phdr->p_type = segment->segmentType();
    phdr->p_offset = segment->fileOffset();
    phdr->p_vaddr = segment->virtualAddr();
    phdr->p_paddr = segment->virtualAddr();
    phdr->p_filesz = segment->fileSize();
    phdr->p_memsz = segment->memSize();
    phdr->p_flags = segment->flags();
    phdr->p_align = segment->alignment();
    this->_fsize = fileSize();
    this->_msize = this->_fsize;
    return allocatedNew;
  }
  // For all other segments, use the slice
  // to derive program headers
  for (auto slice : segment->slices()) {
    Elf_Phdr *phdr = allocateProgramHeader(allocatedNew);
    phdr->p_type = segment->segmentType();
    phdr->p_offset = slice->fileOffset();
    phdr->p_vaddr = slice->virtualAddr();
    phdr->p_paddr = slice->virtualAddr();
    phdr->p_filesz = slice->fileSize();
    phdr->p_memsz = slice->memSize();
    phdr->p_flags = segment->flags();
    phdr->p_align = slice->alignment();
    uint64_t segPageSize = segment->pageSize();
    uint64_t sliceAlign = slice->alignment();
    // Alignment of PT_LOAD segments are set to the page size, but if the
    // alignment of the slice is greater than the page size, set the alignment
    // of the segment appropriately.
    if (outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
        outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) {
      phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD)
          ? (segPageSize < sliceAlign) ? sliceAlign : segPageSize
          : sliceAlign;
    } else
      phdr->p_align = slice->alignment();
  }
  this->_fsize = fileSize();
  this->_msize = this->_fsize;

  return allocatedNew;
}

template <class ELFT>
void ProgramHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
                                llvm::FileOutputBuffer &buffer) {
  uint8_t *chunkBuffer = buffer.getBufferStart();
  uint8_t *dest = chunkBuffer + this->fileOffset();
  for (auto phi : _ph) {
    memcpy(dest, phi, sizeof(Elf_Phdr));
    dest += sizeof(Elf_Phdr);
  }
}

/// \brief An SectionHeader represents the Elf[32/64]_Shdr structure
/// at the end of the file
template<class ELFT>
class SectionHeader : public Chunk<ELFT> {
public:
  typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;

  SectionHeader(const ELFLinkingContext &, int32_t order);

  void appendSection(OutputSection<ELFT> *section);

  void updateSection(Section<ELFT> *section);

  static bool classof(const Chunk<ELFT> *c) {
    return c->getChunkKind() == Chunk<ELFT>::Kind::SectionHeader;
  }

  void setStringSection(StringTable<ELFT> *s) {
    _stringSection = s;
  }

  void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
             llvm::FileOutputBuffer &buffer);

  virtual void doPreFlight() {}

  void finalize() {}

  uint64_t fileSize() const { return sizeof(Elf_Shdr) * _sectionInfo.size(); }

  uint64_t entsize() { return sizeof(Elf_Shdr); }

  int getContentType() const { return Chunk<ELFT>::ContentType::Header; }

  uint64_t numHeaders() { return _sectionInfo.size(); }

private:
  StringTable<ELFT> *_stringSection;
  std::vector<Elf_Shdr*>                  _sectionInfo;
  llvm::BumpPtrAllocator                  _sectionAllocate;
};

template <class ELFT>
SectionHeader<ELFT>::SectionHeader(const ELFLinkingContext &context,
                                   int32_t order)
    : Chunk<ELFT>("shdr", Chunk<ELFT>::Kind::SectionHeader, context) {
  this->_fsize = 0;
  this->_alignment = 8;
  this->setOrder(order);
  // The first element in the list is always NULL
  Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
  ::memset(nullshdr, 0, sizeof (Elf_Shdr));
  _sectionInfo.push_back(nullshdr);
  this->_fsize += sizeof (Elf_Shdr);
}

template <class ELFT>
void SectionHeader<ELFT>::appendSection(OutputSection<ELFT> *section) {
  Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
  shdr->sh_name   = _stringSection->addString(section->name());
  shdr->sh_type   = section->type();
  shdr->sh_flags  = section->flags();
  shdr->sh_offset = section->fileOffset();
  shdr->sh_addr   = section->virtualAddr();
  if (section->isLoadableSection())
    shdr->sh_size = section->memSize();
  else
    shdr->sh_size = section->fileSize();
  shdr->sh_link = section->link();
  shdr->sh_info   = section->shinfo();
  shdr->sh_addralign = section->alignment();
  shdr->sh_entsize = section->entsize();
  _sectionInfo.push_back(shdr);
}

template<class ELFT>
void
SectionHeader<ELFT>::updateSection(Section<ELFT> *section) {
  Elf_Shdr *shdr = _sectionInfo[section->ordinal()];
  shdr->sh_type = section->getType();
  shdr->sh_flags = section->getFlags();
  shdr->sh_offset = section->fileOffset();
  shdr->sh_addr   = section->virtualAddr();
  shdr->sh_size   = section->fileSize();
  shdr->sh_link = section->getLink();
  shdr->sh_info = section->getInfo();
  shdr->sh_addralign = section->alignment();
  shdr->sh_entsize = section->getEntSize();
}

template <class ELFT>
void SectionHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
                                llvm::FileOutputBuffer &buffer) {
  uint8_t *chunkBuffer = buffer.getBufferStart();
  uint8_t *dest = chunkBuffer + this->fileOffset();
  for (auto shi : _sectionInfo) {
    memcpy(dest, shi, sizeof(Elf_Shdr));
    dest += sizeof(Elf_Shdr);
  }
  _stringSection->write(writer, layout, buffer);
}
} // end namespace elf
} // end namespace lld

#endif