blob: 77ac8d913de03811c4621a412132e1919bb2cfa1 [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
45void SectionBase::finalize() {}
46
47template <class ELFT>
48void SectionBase::writeHeader(FileOutputBuffer &Out) const {
49 uint8_t *Buf = Out.getBufferStart();
50 Buf += HeaderOffset;
51 typename ELFT::Shdr &Shdr = *reinterpret_cast<typename ELFT::Shdr *>(Buf);
52 Shdr.sh_name = NameIndex;
53 Shdr.sh_type = Type;
54 Shdr.sh_flags = Flags;
55 Shdr.sh_addr = Addr;
56 Shdr.sh_offset = Offset;
57 Shdr.sh_size = Size;
58 Shdr.sh_link = Link;
59 Shdr.sh_info = Info;
60 Shdr.sh_addralign = Align;
61 Shdr.sh_entsize = EntrySize;
62}
63
64void Section::writeSection(FileOutputBuffer &Out) const {
65 if (Type == SHT_NOBITS)
66 return;
67 uint8_t *Buf = Out.getBufferStart() + Offset;
68 std::copy(std::begin(Contents), std::end(Contents), Buf);
69}
70
71void StringTableSection::addString(StringRef Name) {
72 StrTabBuilder.add(Name);
73 Size = StrTabBuilder.getSize();
74}
75
76uint32_t StringTableSection::findIndex(StringRef Name) const {
77 return StrTabBuilder.getOffset(Name);
78}
79
80void StringTableSection::finalize() { StrTabBuilder.finalize(); }
81
82void StringTableSection::writeSection(FileOutputBuffer &Out) const {
83 StrTabBuilder.write(Out.getBufferStart() + Offset);
84}
85
86// Returns true IFF a section is wholly inside the range of a segment
87static bool sectionWithinSegment(const SectionBase &Section,
88 const Segment &Segment) {
89 // If a section is empty it should be treated like it has a size of 1. This is
90 // to clarify the case when an empty section lies on a boundary between two
91 // segments and ensures that the section "belongs" to the second segment and
92 // not the first.
93 uint64_t SecSize = Section.Size ? Section.Size : 1;
94 return Segment.Offset <= Section.OriginalOffset &&
95 Segment.Offset + Segment.FileSize >= Section.OriginalOffset + SecSize;
96}
97
98template <class ELFT>
99void Object<ELFT>::readProgramHeaders(const ELFFile<ELFT> &ElfFile) {
100 uint32_t Index = 0;
101 for (const auto &Phdr : unwrapOrError(ElfFile.program_headers())) {
102 Segments.emplace_back(llvm::make_unique<Segment>());
103 Segment &Seg = *Segments.back();
104 Seg.Type = Phdr.p_type;
105 Seg.Flags = Phdr.p_flags;
106 Seg.Offset = Phdr.p_offset;
107 Seg.VAddr = Phdr.p_vaddr;
108 Seg.PAddr = Phdr.p_paddr;
109 Seg.FileSize = Phdr.p_filesz;
110 Seg.MemSize = Phdr.p_memsz;
111 Seg.Align = Phdr.p_align;
112 Seg.Index = Index++;
113 for (auto &Section : Sections) {
114 if (sectionWithinSegment(*Section, Seg)) {
115 Seg.addSection(&*Section);
116 if (!Section->ParentSegment ||
117 Section->ParentSegment->Offset > Seg.Offset) {
118 Section->ParentSegment = &Seg;
119 }
120 }
121 }
122 }
123}
124
125template <class ELFT>
126std::unique_ptr<SectionBase>
127Object<ELFT>::makeSection(const llvm::object::ELFFile<ELFT> &ElfFile,
128 const Elf_Shdr &Shdr) {
129 ArrayRef<uint8_t> Data;
130 switch (Shdr.sh_type) {
131 case SHT_STRTAB:
132 return llvm::make_unique<StringTableSection>();
133 case SHT_NOBITS:
134 return llvm::make_unique<Section>(Data);
135 default:
136 Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
137 return llvm::make_unique<Section>(Data);
138 };
139}
140
141template <class ELFT>
142void Object<ELFT>::readSectionHeaders(const ELFFile<ELFT> &ElfFile) {
143 uint32_t Index = 0;
144 for (const auto &Shdr : unwrapOrError(ElfFile.sections())) {
145 if (Index == 0) {
146 ++Index;
147 continue;
148 }
149 SecPtr Sec = makeSection(ElfFile, Shdr);
150 Sec->Name = unwrapOrError(ElfFile.getSectionName(&Shdr));
151 Sec->Type = Shdr.sh_type;
152 Sec->Flags = Shdr.sh_flags;
153 Sec->Addr = Shdr.sh_addr;
154 Sec->Offset = Shdr.sh_offset;
155 Sec->OriginalOffset = Shdr.sh_offset;
156 Sec->Size = Shdr.sh_size;
157 Sec->Link = Shdr.sh_link;
158 Sec->Info = Shdr.sh_info;
159 Sec->Align = Shdr.sh_addralign;
160 Sec->EntrySize = Shdr.sh_entsize;
161 Sec->Index = Index++;
162 Sections.push_back(std::move(Sec));
163 }
164}
165
166template <class ELFT> size_t Object<ELFT>::totalSize() const {
167 // We already have the section header offset so we can calculate the total
168 // size by just adding up the size of each section header.
169 return SHOffset + Sections.size() * sizeof(Elf_Shdr) + sizeof(Elf_Shdr);
170}
171
172template <class ELFT> Object<ELFT>::Object(const ELFObjectFile<ELFT> &Obj) {
173 const auto &ElfFile = *Obj.getELFFile();
174 const auto &Ehdr = *ElfFile.getHeader();
175
176 std::copy(Ehdr.e_ident, Ehdr.e_ident + 16, Ident);
177 Type = Ehdr.e_type;
178 Machine = Ehdr.e_machine;
179 Version = Ehdr.e_version;
180 Entry = Ehdr.e_entry;
181 Flags = Ehdr.e_flags;
182
183 readSectionHeaders(ElfFile);
184 readProgramHeaders(ElfFile);
185
186 SectionNames =
187 dyn_cast<StringTableSection>(Sections[Ehdr.e_shstrndx - 1].get());
188}
189
190template <class ELFT> void Object<ELFT>::sortSections() {
191 // Put all sections in offset order. Maintain the ordering as closely as
192 // possible while meeting that demand however.
193 auto CompareSections = [](const SecPtr &A, const SecPtr &B) {
194 return A->OriginalOffset < B->OriginalOffset;
195 };
196 std::stable_sort(std::begin(Sections), std::end(Sections), CompareSections);
197}
198
199template <class ELFT> void Object<ELFT>::assignOffsets() {
200 // Decide file offsets and indexes.
201 size_t PhdrSize = Segments.size() * sizeof(Elf_Phdr);
202 // We can put section data after the ELF header and the program headers.
203 uint64_t Offset = sizeof(Elf_Ehdr) + PhdrSize;
204 uint64_t Index = 1;
205 for (auto &Section : Sections) {
206 // The segment can have a different alignment than the section. In the case
207 // that there is a parent segment then as long as we satisfy the alignment
208 // of the segment it should follow that that the section is aligned.
209 if (Section->ParentSegment) {
210 auto FirstInSeg = Section->ParentSegment->firstSection();
211 if (FirstInSeg == Section.get()) {
212 Offset = alignTo(Offset, Section->ParentSegment->Align);
213 // There can be gaps at the start of a segment before the first section.
214 // So first we assign the alignment of the segment and then assign the
215 // location of the section from there
216 Section->Offset =
217 Offset + Section->OriginalOffset - Section->ParentSegment->Offset;
218 }
219 // We should respect interstitial gaps of allocated sections. We *must*
220 // maintain the memory image so that addresses are preserved. As, with the
221 // exception of SHT_NOBITS sections at the end of segments, the memory
222 // image is a copy of the file image, we preserve the file image as well.
223 // There's a strange case where a thread local SHT_NOBITS can cause the
224 // memory image and file image to not be the same. This occurs, on some
225 // systems, when a thread local SHT_NOBITS is between two SHT_PROGBITS
226 // and the thread local SHT_NOBITS section is at the end of a TLS segment.
227 // In this case to faithfully copy the segment file image we must use
228 // relative offsets. In any other case this would be the same as using the
229 // relative addresses so this should maintian the memory image as desired.
230 Offset = FirstInSeg->Offset + Section->OriginalOffset -
231 FirstInSeg->OriginalOffset;
232 }
233 // Alignment should have already been handled by the above if statement if
234 // this if this section is in a segment. Technically this shouldn't do
235 // anything bad if the alignments of the sections are all correct and the
236 // file image isn't corrupted. Still in sticking with the motto "maintain
237 // the file image" we should avoid messing up the file image if the
238 // alignment disagrees with the file image.
239 if (!Section->ParentSegment && Section->Align)
240 Offset = alignTo(Offset, Section->Align);
241 Section->Offset = Offset;
242 Section->Index = Index++;
243 if (Section->Type != SHT_NOBITS)
244 Offset += Section->Size;
245 }
246 // 'offset' should now be just after all the section data so we should set the
247 // section header table offset to be exactly here. This spot might not be
248 // aligned properly however so we should align it as needed. For 32-bit ELF
249 // this needs to be 4-byte aligned and on 64-bit it needs to be 8-byte aligned
250 // so the size of ELFT::Addr is used to ensure this.
251 Offset = alignTo(Offset, sizeof(typename ELFT::Addr));
252 SHOffset = Offset;
253}
254
255template <class ELFT> void Object<ELFT>::finalize() {
256 for (auto &Section : Sections)
257 SectionNames->addString(Section->Name);
258
259 sortSections();
260 assignOffsets();
261
262 // Finalize SectionNames first so that we can assign name indexes.
263 SectionNames->finalize();
264 // Finally now that all offsets and indexes have been set we can finalize any
265 // remaining issues.
266 uint64_t Offset = SHOffset + sizeof(Elf_Shdr);
267 for (auto &Section : Sections) {
268 Section->HeaderOffset = Offset;
269 Offset += sizeof(Elf_Shdr);
270 Section->NameIndex = SectionNames->findIndex(Section->Name);
271 Section->finalize();
272 }
273
274 for (auto &Segment : Segments)
275 Segment->finalize();
276}
277
278template <class ELFT>
279void Object<ELFT>::writeHeader(FileOutputBuffer &Out) const {
280 uint8_t *Buf = Out.getBufferStart();
281 Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf);
282 std::copy(Ident, Ident + 16, Ehdr.e_ident);
283 Ehdr.e_type = Type;
284 Ehdr.e_machine = Machine;
285 Ehdr.e_version = Version;
286 Ehdr.e_entry = Entry;
287 Ehdr.e_phoff = sizeof(Elf_Ehdr);
288 Ehdr.e_shoff = SHOffset;
289 Ehdr.e_flags = Flags;
290 Ehdr.e_ehsize = sizeof(Elf_Ehdr);
291 Ehdr.e_phentsize = sizeof(Elf_Phdr);
292 Ehdr.e_phnum = Segments.size();
293 Ehdr.e_shentsize = sizeof(Elf_Shdr);
294 Ehdr.e_shnum = Sections.size() + 1;
295 Ehdr.e_shstrndx = SectionNames->Index;
296}
297
298template <class ELFT>
299void Object<ELFT>::writeProgramHeaders(FileOutputBuffer &Out) const {
300 for (auto &Phdr : Segments)
301 Phdr->template writeHeader<ELFT>(Out);
302}
303
304template <class ELFT>
305void Object<ELFT>::writeSectionHeaders(FileOutputBuffer &Out) const {
306 uint8_t *Buf = Out.getBufferStart() + SHOffset;
307 // This reference serves to write the dummy section header at the begining
308 // of the file.
309 Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(Buf);
310 Shdr.sh_name = 0;
311 Shdr.sh_type = SHT_NULL;
312 Shdr.sh_flags = 0;
313 Shdr.sh_addr = 0;
314 Shdr.sh_offset = 0;
315 Shdr.sh_size = 0;
316 Shdr.sh_link = 0;
317 Shdr.sh_info = 0;
318 Shdr.sh_addralign = 0;
319 Shdr.sh_entsize = 0;
320
321 for (auto &Section : Sections)
322 Section->template writeHeader<ELFT>(Out);
323}
324
325template <class ELFT>
326void Object<ELFT>::writeSectionData(FileOutputBuffer &Out) const {
327 for (auto &Section : Sections)
328 Section->writeSection(Out);
329}
330
331template <class ELFT> void Object<ELFT>::write(FileOutputBuffer &Out) {
332 writeHeader(Out);
333 writeProgramHeaders(Out);
334 writeSectionData(Out);
335 writeSectionHeaders(Out);
336}
337
338template class Object<ELF64LE>;
339template class Object<ELF64BE>;
340template class Object<ELF32LE>;
341template class Object<ELF32BE>;