blob: c57dfe005eddec8290ba95d9fa3006d536719ecb [file] [log] [blame]
Petr Hosek05a04cb2017-08-01 00:33:58 +00001//===- Object.cpp -----------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include "Object.h"
10#include "llvm-objcopy.h"
11
12using namespace llvm;
13using namespace object;
14using namespace ELF;
15
16template <class ELFT> void Segment::writeHeader(FileOutputBuffer &Out) const {
17 typedef typename ELFT::Ehdr Elf_Ehdr;
18 typedef typename ELFT::Phdr Elf_Phdr;
19
20 uint8_t *Buf = Out.getBufferStart();
21 Buf += sizeof(Elf_Ehdr) + Index * sizeof(Elf_Phdr);
22 Elf_Phdr &Phdr = *reinterpret_cast<Elf_Phdr *>(Buf);
23 Phdr.p_type = Type;
24 Phdr.p_flags = Flags;
25 Phdr.p_offset = Offset;
26 Phdr.p_vaddr = VAddr;
27 Phdr.p_paddr = PAddr;
28 Phdr.p_filesz = FileSize;
29 Phdr.p_memsz = MemSize;
30 Phdr.p_align = Align;
31}
32
33void Segment::finalize() {
34 auto FirstSec = firstSection();
35 if (FirstSec) {
36 // It is possible for a gap to be at the begining of a segment. Because of
37 // this we need to compute the new offset based on how large this gap was
38 // in the source file. Section layout should have already ensured that this
39 // space is not used for something else.
40 uint64_t OriginalOffset = Offset;
41 Offset = FirstSec->Offset - (FirstSec->OriginalOffset - OriginalOffset);
42 }
43}
44
Petr Hosek8882ac22017-08-01 05:18:30 +000045void Segment::writeSegment(FileOutputBuffer &Out) const {
46 uint8_t *Buf = Out.getBufferStart() + Offset;
47 // We want to maintain segments' interstitial data and contents exactly.
48 // This lets us just copy segments directly.
49 std::copy(std::begin(Contents), std::end(Contents), Buf);
50}
51
Petr Hosek05a04cb2017-08-01 00:33:58 +000052void SectionBase::finalize() {}
53
54template <class ELFT>
55void SectionBase::writeHeader(FileOutputBuffer &Out) const {
56 uint8_t *Buf = Out.getBufferStart();
57 Buf += HeaderOffset;
58 typename ELFT::Shdr &Shdr = *reinterpret_cast<typename ELFT::Shdr *>(Buf);
59 Shdr.sh_name = NameIndex;
60 Shdr.sh_type = Type;
61 Shdr.sh_flags = Flags;
62 Shdr.sh_addr = Addr;
63 Shdr.sh_offset = Offset;
64 Shdr.sh_size = Size;
65 Shdr.sh_link = Link;
66 Shdr.sh_info = Info;
67 Shdr.sh_addralign = Align;
68 Shdr.sh_entsize = EntrySize;
69}
70
71void Section::writeSection(FileOutputBuffer &Out) const {
72 if (Type == SHT_NOBITS)
73 return;
74 uint8_t *Buf = Out.getBufferStart() + Offset;
75 std::copy(std::begin(Contents), std::end(Contents), Buf);
76}
77
78void StringTableSection::addString(StringRef Name) {
79 StrTabBuilder.add(Name);
80 Size = StrTabBuilder.getSize();
81}
82
83uint32_t StringTableSection::findIndex(StringRef Name) const {
84 return StrTabBuilder.getOffset(Name);
85}
86
87void StringTableSection::finalize() { StrTabBuilder.finalize(); }
88
89void StringTableSection::writeSection(FileOutputBuffer &Out) const {
90 StrTabBuilder.write(Out.getBufferStart() + Offset);
91}
92
93// Returns true IFF a section is wholly inside the range of a segment
94static bool sectionWithinSegment(const SectionBase &Section,
95 const Segment &Segment) {
96 // If a section is empty it should be treated like it has a size of 1. This is
97 // to clarify the case when an empty section lies on a boundary between two
98 // segments and ensures that the section "belongs" to the second segment and
99 // not the first.
100 uint64_t SecSize = Section.Size ? Section.Size : 1;
101 return Segment.Offset <= Section.OriginalOffset &&
102 Segment.Offset + Segment.FileSize >= Section.OriginalOffset + SecSize;
103}
104
105template <class ELFT>
106void Object<ELFT>::readProgramHeaders(const ELFFile<ELFT> &ElfFile) {
107 uint32_t Index = 0;
108 for (const auto &Phdr : unwrapOrError(ElfFile.program_headers())) {
Petr Hosek8882ac22017-08-01 05:18:30 +0000109 ArrayRef<uint8_t> Data{ElfFile.base() + Phdr.p_offset, Phdr.p_filesz};
110 Segments.emplace_back(llvm::make_unique<Segment>(Data));
Petr Hosek05a04cb2017-08-01 00:33:58 +0000111 Segment &Seg = *Segments.back();
112 Seg.Type = Phdr.p_type;
113 Seg.Flags = Phdr.p_flags;
114 Seg.Offset = Phdr.p_offset;
115 Seg.VAddr = Phdr.p_vaddr;
116 Seg.PAddr = Phdr.p_paddr;
117 Seg.FileSize = Phdr.p_filesz;
118 Seg.MemSize = Phdr.p_memsz;
119 Seg.Align = Phdr.p_align;
120 Seg.Index = Index++;
121 for (auto &Section : Sections) {
122 if (sectionWithinSegment(*Section, Seg)) {
123 Seg.addSection(&*Section);
124 if (!Section->ParentSegment ||
125 Section->ParentSegment->Offset > Seg.Offset) {
126 Section->ParentSegment = &Seg;
127 }
128 }
129 }
130 }
131}
132
133template <class ELFT>
134std::unique_ptr<SectionBase>
135Object<ELFT>::makeSection(const llvm::object::ELFFile<ELFT> &ElfFile,
136 const Elf_Shdr &Shdr) {
137 ArrayRef<uint8_t> Data;
138 switch (Shdr.sh_type) {
139 case SHT_STRTAB:
140 return llvm::make_unique<StringTableSection>();
141 case SHT_NOBITS:
142 return llvm::make_unique<Section>(Data);
143 default:
144 Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
145 return llvm::make_unique<Section>(Data);
Petr Hosek8882ac22017-08-01 05:18:30 +0000146 }
Petr Hosek05a04cb2017-08-01 00:33:58 +0000147}
148
149template <class ELFT>
150void Object<ELFT>::readSectionHeaders(const ELFFile<ELFT> &ElfFile) {
151 uint32_t Index = 0;
152 for (const auto &Shdr : unwrapOrError(ElfFile.sections())) {
153 if (Index == 0) {
154 ++Index;
155 continue;
156 }
157 SecPtr Sec = makeSection(ElfFile, Shdr);
158 Sec->Name = unwrapOrError(ElfFile.getSectionName(&Shdr));
159 Sec->Type = Shdr.sh_type;
160 Sec->Flags = Shdr.sh_flags;
161 Sec->Addr = Shdr.sh_addr;
162 Sec->Offset = Shdr.sh_offset;
163 Sec->OriginalOffset = Shdr.sh_offset;
164 Sec->Size = Shdr.sh_size;
165 Sec->Link = Shdr.sh_link;
166 Sec->Info = Shdr.sh_info;
167 Sec->Align = Shdr.sh_addralign;
168 Sec->EntrySize = Shdr.sh_entsize;
169 Sec->Index = Index++;
170 Sections.push_back(std::move(Sec));
171 }
172}
173
Petr Hosek05a04cb2017-08-01 00:33:58 +0000174template <class ELFT> Object<ELFT>::Object(const ELFObjectFile<ELFT> &Obj) {
175 const auto &ElfFile = *Obj.getELFFile();
176 const auto &Ehdr = *ElfFile.getHeader();
177
178 std::copy(Ehdr.e_ident, Ehdr.e_ident + 16, Ident);
179 Type = Ehdr.e_type;
180 Machine = Ehdr.e_machine;
181 Version = Ehdr.e_version;
182 Entry = Ehdr.e_entry;
183 Flags = Ehdr.e_flags;
184
185 readSectionHeaders(ElfFile);
186 readProgramHeaders(ElfFile);
187
188 SectionNames =
189 dyn_cast<StringTableSection>(Sections[Ehdr.e_shstrndx - 1].get());
190}
191
Petr Hosek05a04cb2017-08-01 00:33:58 +0000192template <class ELFT>
193void Object<ELFT>::writeHeader(FileOutputBuffer &Out) const {
194 uint8_t *Buf = Out.getBufferStart();
195 Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf);
196 std::copy(Ident, Ident + 16, Ehdr.e_ident);
197 Ehdr.e_type = Type;
198 Ehdr.e_machine = Machine;
199 Ehdr.e_version = Version;
200 Ehdr.e_entry = Entry;
201 Ehdr.e_phoff = sizeof(Elf_Ehdr);
202 Ehdr.e_shoff = SHOffset;
203 Ehdr.e_flags = Flags;
204 Ehdr.e_ehsize = sizeof(Elf_Ehdr);
205 Ehdr.e_phentsize = sizeof(Elf_Phdr);
206 Ehdr.e_phnum = Segments.size();
207 Ehdr.e_shentsize = sizeof(Elf_Shdr);
208 Ehdr.e_shnum = Sections.size() + 1;
209 Ehdr.e_shstrndx = SectionNames->Index;
210}
211
212template <class ELFT>
213void Object<ELFT>::writeProgramHeaders(FileOutputBuffer &Out) const {
214 for (auto &Phdr : Segments)
215 Phdr->template writeHeader<ELFT>(Out);
216}
217
218template <class ELFT>
219void Object<ELFT>::writeSectionHeaders(FileOutputBuffer &Out) const {
220 uint8_t *Buf = Out.getBufferStart() + SHOffset;
221 // This reference serves to write the dummy section header at the begining
222 // of the file.
223 Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(Buf);
224 Shdr.sh_name = 0;
225 Shdr.sh_type = SHT_NULL;
226 Shdr.sh_flags = 0;
227 Shdr.sh_addr = 0;
228 Shdr.sh_offset = 0;
229 Shdr.sh_size = 0;
230 Shdr.sh_link = 0;
231 Shdr.sh_info = 0;
232 Shdr.sh_addralign = 0;
233 Shdr.sh_entsize = 0;
234
235 for (auto &Section : Sections)
236 Section->template writeHeader<ELFT>(Out);
237}
238
239template <class ELFT>
240void Object<ELFT>::writeSectionData(FileOutputBuffer &Out) const {
241 for (auto &Section : Sections)
242 Section->writeSection(Out);
243}
244
Petr Hosek8882ac22017-08-01 05:18:30 +0000245template <class ELFT> void ELFObject<ELFT>::sortSections() {
246 // Put all sections in offset order. Maintain the ordering as closely as
247 // possible while meeting that demand however.
248 auto CompareSections = [](const SecPtr &A, const SecPtr &B) {
249 return A->OriginalOffset < B->OriginalOffset;
250 };
251 std::stable_sort(std::begin(this->Sections), std::end(this->Sections),
252 CompareSections);
Petr Hosek05a04cb2017-08-01 00:33:58 +0000253}
254
Petr Hosek8882ac22017-08-01 05:18:30 +0000255template <class ELFT> void ELFObject<ELFT>::assignOffsets() {
256 // Decide file offsets and indexes.
257 size_t PhdrSize = this->Segments.size() * sizeof(Elf_Phdr);
258 // We can put section data after the ELF header and the program headers.
259 uint64_t Offset = sizeof(Elf_Ehdr) + PhdrSize;
260 uint64_t Index = 1;
261 for (auto &Section : this->Sections) {
262 // The segment can have a different alignment than the section. In the case
263 // that there is a parent segment then as long as we satisfy the alignment
264 // of the segment it should follow that that the section is aligned.
265 if (Section->ParentSegment) {
266 auto FirstInSeg = Section->ParentSegment->firstSection();
267 if (FirstInSeg == Section.get()) {
268 Offset = alignTo(Offset, Section->ParentSegment->Align);
269 // There can be gaps at the start of a segment before the first section.
270 // So first we assign the alignment of the segment and then assign the
271 // location of the section from there
272 Section->Offset =
273 Offset + Section->OriginalOffset - Section->ParentSegment->Offset;
274 }
275 // We should respect interstitial gaps of allocated sections. We *must*
276 // maintain the memory image so that addresses are preserved. As, with the
277 // exception of SHT_NOBITS sections at the end of segments, the memory
278 // image is a copy of the file image, we preserve the file image as well.
279 // There's a strange case where a thread local SHT_NOBITS can cause the
280 // memory image and file image to not be the same. This occurs, on some
281 // systems, when a thread local SHT_NOBITS is between two SHT_PROGBITS
282 // and the thread local SHT_NOBITS section is at the end of a TLS segment.
283 // In this case to faithfully copy the segment file image we must use
284 // relative offsets. In any other case this would be the same as using the
285 // relative addresses so this should maintian the memory image as desired.
286 Offset = FirstInSeg->Offset + Section->OriginalOffset -
287 FirstInSeg->OriginalOffset;
288 }
289 // Alignment should have already been handled by the above if statement if
290 // this if this section is in a segment. Technically this shouldn't do
291 // anything bad if the alignments of the sections are all correct and the
292 // file image isn't corrupted. Still in sticking with the motto "maintain
293 // the file image" we should avoid messing up the file image if the
294 // alignment disagrees with the file image.
295 if (!Section->ParentSegment && Section->Align)
296 Offset = alignTo(Offset, Section->Align);
297 Section->Offset = Offset;
298 Section->Index = Index++;
299 if (Section->Type != SHT_NOBITS)
300 Offset += Section->Size;
301 }
302 // 'offset' should now be just after all the section data so we should set the
303 // section header table offset to be exactly here. This spot might not be
304 // aligned properly however so we should align it as needed. For 32-bit ELF
305 // this needs to be 4-byte aligned and on 64-bit it needs to be 8-byte aligned
306 // so the size of ELFT::Addr is used to ensure this.
307 Offset = alignTo(Offset, sizeof(typename ELFT::Addr));
308 this->SHOffset = Offset;
309}
310
311template <class ELFT> size_t ELFObject<ELFT>::totalSize() const {
312 // We already have the section header offset so we can calculate the total
313 // size by just adding up the size of each section header.
314 return this->SHOffset + this->Sections.size() * sizeof(Elf_Shdr) +
315 sizeof(Elf_Shdr);
316}
317
318template <class ELFT> void ELFObject<ELFT>::write(FileOutputBuffer &Out) const {
319 this->writeHeader(Out);
320 this->writeProgramHeaders(Out);
321 this->writeSectionData(Out);
322 this->writeSectionHeaders(Out);
323}
324
325template <class ELFT> void ELFObject<ELFT>::finalize() {
326 for (const auto &Section : this->Sections) {
327 this->SectionNames->addString(Section->Name);
328 }
329
330 sortSections();
331 assignOffsets();
332
333 // Finalize SectionNames first so that we can assign name indexes.
334 this->SectionNames->finalize();
335 // Finally now that all offsets and indexes have been set we can finalize any
336 // remaining issues.
337 uint64_t Offset = this->SHOffset + sizeof(Elf_Shdr);
338 for (auto &Section : this->Sections) {
339 Section->HeaderOffset = Offset;
340 Offset += sizeof(Elf_Shdr);
341 Section->NameIndex = this->SectionNames->findIndex(Section->Name);
342 Section->finalize();
343 }
344
345 for (auto &Segment : this->Segments)
346 Segment->finalize();
347}
348
349template <class ELFT> size_t BinaryObject<ELFT>::totalSize() const {
350 return TotalSize;
351}
352
353template <class ELFT>
354void BinaryObject<ELFT>::write(FileOutputBuffer &Out) const {
355 for (auto &Segment : this->Segments) {
356 if (Segment->Type == llvm::ELF::PT_LOAD) {
357 Segment->writeSegment(Out);
358 }
359 }
360}
361
362template <class ELFT> void BinaryObject<ELFT>::finalize() {
363 for (auto &Segment : this->Segments)
364 Segment->finalize();
365
366 // Put all segments in offset order.
367 auto CompareSegments = [](const SegPtr &A, const SegPtr &B) {
368 return A->Offset < B->Offset;
369 };
370 std::sort(std::begin(this->Segments), std::end(this->Segments),
371 CompareSegments);
372
373 uint64_t Offset = 0;
374 for (auto &Segment : this->Segments) {
375 if (Segment->Type == llvm::ELF::PT_LOAD) {
376 Offset = alignTo(Offset, Segment->Align);
377 Segment->Offset = Offset;
378 Offset += Segment->FileSize;
379 }
380 }
381 TotalSize = Offset;
382}
383
384template class ELFObject<ELF64LE>;
385template class ELFObject<ELF64BE>;
386template class ELFObject<ELF32LE>;
387template class ELFObject<ELF32BE>;
388
389template class BinaryObject<ELF64LE>;
390template class BinaryObject<ELF64BE>;
391template class BinaryObject<ELF32LE>;
392template class BinaryObject<ELF32BE>;