blob: 55f8855f50f7bb5f7e93e05b337e090ce2edf09c [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 Hosekc4df10e2017-08-04 21:09:26 +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 Hosekc4df10e2017-08-04 21:09:26 +0000109 ArrayRef<uint8_t> Data{ElfFile.base() + Phdr.p_offset,
110 (size_t)Phdr.p_filesz};
111 Segments.emplace_back(llvm::make_unique<Segment>(Data));
Petr Hosek05a04cb2017-08-01 00:33:58 +0000112 Segment &Seg = *Segments.back();
113 Seg.Type = Phdr.p_type;
114 Seg.Flags = Phdr.p_flags;
Petr Hosek3f383832017-08-26 01:32:20 +0000115 Seg.OriginalOffset = Phdr.p_offset;
Petr Hosek05a04cb2017-08-01 00:33:58 +0000116 Seg.Offset = Phdr.p_offset;
117 Seg.VAddr = Phdr.p_vaddr;
118 Seg.PAddr = Phdr.p_paddr;
119 Seg.FileSize = Phdr.p_filesz;
120 Seg.MemSize = Phdr.p_memsz;
121 Seg.Align = Phdr.p_align;
122 Seg.Index = Index++;
123 for (auto &Section : Sections) {
124 if (sectionWithinSegment(*Section, Seg)) {
125 Seg.addSection(&*Section);
126 if (!Section->ParentSegment ||
127 Section->ParentSegment->Offset > Seg.Offset) {
128 Section->ParentSegment = &Seg;
129 }
130 }
131 }
132 }
133}
134
135template <class ELFT>
136std::unique_ptr<SectionBase>
137Object<ELFT>::makeSection(const llvm::object::ELFFile<ELFT> &ElfFile,
138 const Elf_Shdr &Shdr) {
139 ArrayRef<uint8_t> Data;
140 switch (Shdr.sh_type) {
141 case SHT_STRTAB:
142 return llvm::make_unique<StringTableSection>();
143 case SHT_NOBITS:
144 return llvm::make_unique<Section>(Data);
145 default:
146 Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
147 return llvm::make_unique<Section>(Data);
Petr Hosekc4df10e2017-08-04 21:09:26 +0000148 }
Petr Hosek05a04cb2017-08-01 00:33:58 +0000149}
150
151template <class ELFT>
152void Object<ELFT>::readSectionHeaders(const ELFFile<ELFT> &ElfFile) {
153 uint32_t Index = 0;
154 for (const auto &Shdr : unwrapOrError(ElfFile.sections())) {
155 if (Index == 0) {
156 ++Index;
157 continue;
158 }
159 SecPtr Sec = makeSection(ElfFile, Shdr);
160 Sec->Name = unwrapOrError(ElfFile.getSectionName(&Shdr));
161 Sec->Type = Shdr.sh_type;
162 Sec->Flags = Shdr.sh_flags;
163 Sec->Addr = Shdr.sh_addr;
164 Sec->Offset = Shdr.sh_offset;
165 Sec->OriginalOffset = Shdr.sh_offset;
166 Sec->Size = Shdr.sh_size;
167 Sec->Link = Shdr.sh_link;
168 Sec->Info = Shdr.sh_info;
169 Sec->Align = Shdr.sh_addralign;
170 Sec->EntrySize = Shdr.sh_entsize;
171 Sec->Index = Index++;
172 Sections.push_back(std::move(Sec));
173 }
174}
175
Petr Hosek05a04cb2017-08-01 00:33:58 +0000176template <class ELFT> Object<ELFT>::Object(const ELFObjectFile<ELFT> &Obj) {
177 const auto &ElfFile = *Obj.getELFFile();
178 const auto &Ehdr = *ElfFile.getHeader();
179
180 std::copy(Ehdr.e_ident, Ehdr.e_ident + 16, Ident);
181 Type = Ehdr.e_type;
182 Machine = Ehdr.e_machine;
183 Version = Ehdr.e_version;
184 Entry = Ehdr.e_entry;
185 Flags = Ehdr.e_flags;
186
187 readSectionHeaders(ElfFile);
188 readProgramHeaders(ElfFile);
189
190 SectionNames =
191 dyn_cast<StringTableSection>(Sections[Ehdr.e_shstrndx - 1].get());
192}
193
Petr Hosek05a04cb2017-08-01 00:33:58 +0000194template <class ELFT>
195void Object<ELFT>::writeHeader(FileOutputBuffer &Out) const {
196 uint8_t *Buf = Out.getBufferStart();
197 Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf);
198 std::copy(Ident, Ident + 16, Ehdr.e_ident);
199 Ehdr.e_type = Type;
200 Ehdr.e_machine = Machine;
201 Ehdr.e_version = Version;
202 Ehdr.e_entry = Entry;
203 Ehdr.e_phoff = sizeof(Elf_Ehdr);
204 Ehdr.e_shoff = SHOffset;
205 Ehdr.e_flags = Flags;
206 Ehdr.e_ehsize = sizeof(Elf_Ehdr);
207 Ehdr.e_phentsize = sizeof(Elf_Phdr);
208 Ehdr.e_phnum = Segments.size();
209 Ehdr.e_shentsize = sizeof(Elf_Shdr);
210 Ehdr.e_shnum = Sections.size() + 1;
211 Ehdr.e_shstrndx = SectionNames->Index;
212}
213
214template <class ELFT>
215void Object<ELFT>::writeProgramHeaders(FileOutputBuffer &Out) const {
216 for (auto &Phdr : Segments)
217 Phdr->template writeHeader<ELFT>(Out);
218}
219
220template <class ELFT>
221void Object<ELFT>::writeSectionHeaders(FileOutputBuffer &Out) const {
222 uint8_t *Buf = Out.getBufferStart() + SHOffset;
223 // This reference serves to write the dummy section header at the begining
224 // of the file.
225 Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(Buf);
226 Shdr.sh_name = 0;
227 Shdr.sh_type = SHT_NULL;
228 Shdr.sh_flags = 0;
229 Shdr.sh_addr = 0;
230 Shdr.sh_offset = 0;
231 Shdr.sh_size = 0;
232 Shdr.sh_link = 0;
233 Shdr.sh_info = 0;
234 Shdr.sh_addralign = 0;
235 Shdr.sh_entsize = 0;
236
237 for (auto &Section : Sections)
238 Section->template writeHeader<ELFT>(Out);
239}
240
241template <class ELFT>
242void Object<ELFT>::writeSectionData(FileOutputBuffer &Out) const {
243 for (auto &Section : Sections)
244 Section->writeSection(Out);
245}
246
Petr Hosekc4df10e2017-08-04 21:09:26 +0000247template <class ELFT> void ELFObject<ELFT>::sortSections() {
248 // Put all sections in offset order. Maintain the ordering as closely as
249 // possible while meeting that demand however.
250 auto CompareSections = [](const SecPtr &A, const SecPtr &B) {
251 return A->OriginalOffset < B->OriginalOffset;
252 };
253 std::stable_sort(std::begin(this->Sections), std::end(this->Sections),
254 CompareSections);
255}
256
257template <class ELFT> void ELFObject<ELFT>::assignOffsets() {
Petr Hosek3f383832017-08-26 01:32:20 +0000258 // The size of ELF + program headers will not change so it is ok to assume
259 // that the first offset of the first segment is a good place to start
260 // outputting sections. This covers both the standard case and the PT_PHDR
261 // case.
262 uint64_t Offset;
263 if (!this->Segments.empty()) {
264 Offset = this->Segments[0]->Offset;
265 } else {
266 Offset = sizeof(Elf_Ehdr);
Petr Hosekc4df10e2017-08-04 21:09:26 +0000267 }
Petr Hosek3f383832017-08-26 01:32:20 +0000268 // The only way a segment should move is if a section was between two
269 // segments and that section was removed. If that section isn't in a segment
270 // then it's acceptable, but not ideal, to simply move it to after the
271 // segments. So we can simply layout segments one after the other accounting
272 // for alignment.
273 for (auto &Segment : this->Segments) {
274 Offset = alignTo(Offset, Segment->Align);
275 Segment->Offset = Offset;
276 Offset += Segment->FileSize;
277 }
278 // Now the offset of every segment has been set we can assign the offsets
279 // of each section. For sections that are covered by a segment we should use
280 // the segment's original offset and the section's original offset to compute
281 // the offset from the start of the segment. Using the offset from the start
282 // of the segment we can assign a new offset to the section. For sections not
283 // covered by segments we can just bump Offset to the next valid location.
284 uint32_t Index = 1;
285 for (auto &Section : this->Sections) {
286 Section->Index = Index++;
287 if (Section->ParentSegment != nullptr) {
288 auto Segment = Section->ParentSegment;
289 Section->Offset =
290 Segment->Offset + (Section->OriginalOffset - Segment->OriginalOffset);
291 } else {
292 Offset = alignTo(Offset, Section->Offset);
293 Section->Offset = Offset;
294 if (Section->Type != SHT_NOBITS)
295 Offset += Section->Size;
296 }
297 }
298
Petr Hosekc4df10e2017-08-04 21:09:26 +0000299 Offset = alignTo(Offset, sizeof(typename ELFT::Addr));
300 this->SHOffset = Offset;
301}
302
303template <class ELFT> size_t ELFObject<ELFT>::totalSize() const {
304 // We already have the section header offset so we can calculate the total
305 // size by just adding up the size of each section header.
306 return this->SHOffset + this->Sections.size() * sizeof(Elf_Shdr) +
307 sizeof(Elf_Shdr);
308}
309
310template <class ELFT> void ELFObject<ELFT>::write(FileOutputBuffer &Out) const {
311 this->writeHeader(Out);
312 this->writeProgramHeaders(Out);
313 this->writeSectionData(Out);
314 this->writeSectionHeaders(Out);
315}
316
317template <class ELFT> void ELFObject<ELFT>::finalize() {
318 for (const auto &Section : this->Sections) {
319 this->SectionNames->addString(Section->Name);
320 }
321
322 sortSections();
323 assignOffsets();
324
325 // Finalize SectionNames first so that we can assign name indexes.
326 this->SectionNames->finalize();
327 // Finally now that all offsets and indexes have been set we can finalize any
328 // remaining issues.
329 uint64_t Offset = this->SHOffset + sizeof(Elf_Shdr);
330 for (auto &Section : this->Sections) {
331 Section->HeaderOffset = Offset;
332 Offset += sizeof(Elf_Shdr);
333 Section->NameIndex = this->SectionNames->findIndex(Section->Name);
334 Section->finalize();
335 }
336
337 for (auto &Segment : this->Segments)
338 Segment->finalize();
339}
340
341template <class ELFT> size_t BinaryObject<ELFT>::totalSize() const {
342 return TotalSize;
343}
344
345template <class ELFT>
346void BinaryObject<ELFT>::write(FileOutputBuffer &Out) const {
347 for (auto &Segment : this->Segments) {
Petr Hosekd53951d2017-08-04 23:18:18 +0000348 // GNU objcopy does not output segments that do not cover a section. Such
349 // segments can sometimes be produced by LLD due to how LLD handles PT_PHDR.
350 if (Segment->Type == llvm::ELF::PT_LOAD &&
351 Segment->firstSection() != nullptr) {
Petr Hosekc4df10e2017-08-04 21:09:26 +0000352 Segment->writeSegment(Out);
353 }
354 }
355}
356
357template <class ELFT> void BinaryObject<ELFT>::finalize() {
358 for (auto &Segment : this->Segments)
359 Segment->finalize();
360
361 // Put all segments in offset order.
362 auto CompareSegments = [](const SegPtr &A, const SegPtr &B) {
363 return A->Offset < B->Offset;
364 };
365 std::sort(std::begin(this->Segments), std::end(this->Segments),
366 CompareSegments);
367
368 uint64_t Offset = 0;
369 for (auto &Segment : this->Segments) {
Petr Hosekd53951d2017-08-04 23:18:18 +0000370 if (Segment->Type == llvm::ELF::PT_LOAD &&
371 Segment->firstSection() != nullptr) {
Petr Hosekc4df10e2017-08-04 21:09:26 +0000372 Offset = alignTo(Offset, Segment->Align);
373 Segment->Offset = Offset;
374 Offset += Segment->FileSize;
375 }
376 }
377 TotalSize = Offset;
Petr Hosek05a04cb2017-08-01 00:33:58 +0000378}
379
Petr Hosek35fdbd52017-08-01 05:31:50 +0000380template class Object<ELF64LE>;
381template class Object<ELF64BE>;
382template class Object<ELF32LE>;
383template class Object<ELF32BE>;
Petr Hosekc4df10e2017-08-04 21:09:26 +0000384
385template class ELFObject<ELF64LE>;
386template class ELFObject<ELF64BE>;
387template class ELFObject<ELF32LE>;
388template class ELFObject<ELF32BE>;
389
390template class BinaryObject<ELF64LE>;
391template class BinaryObject<ELF64BE>;
392template class BinaryObject<ELF32LE>;
393template class BinaryObject<ELF32BE>;