1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #undef NDEBUG
6 #include <cstring>
7 #include <assert.h>
8 #include "elfxx.h"
9
10 template <class endian, typename R, typename T>
swap(T & t,R & r)11 void Elf_Ehdr_Traits::swap(T& t, R& r) {
12 memcpy(r.e_ident, t.e_ident, sizeof(r.e_ident));
13 r.e_type = endian::swap(t.e_type);
14 r.e_machine = endian::swap(t.e_machine);
15 r.e_version = endian::swap(t.e_version);
16 r.e_entry = endian::swap(t.e_entry);
17 r.e_phoff = endian::swap(t.e_phoff);
18 r.e_shoff = endian::swap(t.e_shoff);
19 r.e_flags = endian::swap(t.e_flags);
20 r.e_ehsize = endian::swap(t.e_ehsize);
21 r.e_phentsize = endian::swap(t.e_phentsize);
22 r.e_phnum = endian::swap(t.e_phnum);
23 r.e_shentsize = endian::swap(t.e_shentsize);
24 r.e_shnum = endian::swap(t.e_shnum);
25 r.e_shstrndx = endian::swap(t.e_shstrndx);
26 }
27
28 template <class endian, typename R, typename T>
swap(T & t,R & r)29 void Elf_Phdr_Traits::swap(T& t, R& r) {
30 r.p_type = endian::swap(t.p_type);
31 r.p_offset = endian::swap(t.p_offset);
32 r.p_vaddr = endian::swap(t.p_vaddr);
33 r.p_paddr = endian::swap(t.p_paddr);
34 r.p_filesz = endian::swap(t.p_filesz);
35 r.p_memsz = endian::swap(t.p_memsz);
36 r.p_flags = endian::swap(t.p_flags);
37 r.p_align = endian::swap(t.p_align);
38 }
39
40 template <class endian, typename R, typename T>
swap(T & t,R & r)41 void Elf_Shdr_Traits::swap(T& t, R& r) {
42 r.sh_name = endian::swap(t.sh_name);
43 r.sh_type = endian::swap(t.sh_type);
44 r.sh_flags = endian::swap(t.sh_flags);
45 r.sh_addr = endian::swap(t.sh_addr);
46 r.sh_offset = endian::swap(t.sh_offset);
47 r.sh_size = endian::swap(t.sh_size);
48 r.sh_link = endian::swap(t.sh_link);
49 r.sh_info = endian::swap(t.sh_info);
50 r.sh_addralign = endian::swap(t.sh_addralign);
51 r.sh_entsize = endian::swap(t.sh_entsize);
52 }
53
54 template <class endian, typename R, typename T>
swap(T & t,R & r)55 void Elf_Dyn_Traits::swap(T& t, R& r) {
56 r.d_tag = endian::swap(t.d_tag);
57 r.d_un.d_val = endian::swap(t.d_un.d_val);
58 }
59
60 template <class endian, typename R, typename T>
swap(T & t,R & r)61 void Elf_Sym_Traits::swap(T& t, R& r) {
62 r.st_name = endian::swap(t.st_name);
63 r.st_value = endian::swap(t.st_value);
64 r.st_size = endian::swap(t.st_size);
65 r.st_info = t.st_info;
66 r.st_other = t.st_other;
67 r.st_shndx = endian::swap(t.st_shndx);
68 }
69
70 template <class endian>
71 struct _Rel_info {
swap_Rel_info72 static inline void swap(Elf32_Word& t, Elf32_Word& r) { r = endian::swap(t); }
swap_Rel_info73 static inline void swap(Elf64_Xword& t, Elf64_Xword& r) {
74 r = endian::swap(t);
75 }
swap_Rel_info76 static inline void swap(Elf64_Xword& t, Elf32_Word& r) {
77 r = endian::swap(ELF32_R_INFO(ELF64_R_SYM(t), ELF64_R_TYPE(t)));
78 }
swap_Rel_info79 static inline void swap(Elf32_Word& t, Elf64_Xword& r) {
80 r = endian::swap(ELF64_R_INFO(ELF32_R_SYM(t), ELF32_R_TYPE(t)));
81 }
82 };
83
84 template <class endian, typename R, typename T>
swap(T & t,R & r)85 void Elf_Rel_Traits::swap(T& t, R& r) {
86 r.r_offset = endian::swap(t.r_offset);
87 _Rel_info<endian>::swap(t.r_info, r.r_info);
88 }
89
90 template <class endian, typename R, typename T>
swap(T & t,R & r)91 void Elf_Rela_Traits::swap(T& t, R& r) {
92 r.r_offset = endian::swap(t.r_offset);
93 _Rel_info<endian>::swap(t.r_info, r.r_info);
94 r.r_addend = endian::swap(t.r_addend);
95 }
96
97 static const Elf64_Shdr null64_section = {0, SHT_NULL, 0, 0, 0,
98 0, SHN_UNDEF, 0, 0, 0};
99
100 Elf_Shdr null_section(null64_section);
101
Elf_Ehdr(std::ifstream & file,unsigned char ei_class,unsigned char ei_data)102 Elf_Ehdr::Elf_Ehdr(std::ifstream& file, unsigned char ei_class,
103 unsigned char ei_data)
104 : serializable<Elf_Ehdr_Traits>(file, ei_class, ei_data),
105 ElfSection(null_section, nullptr, nullptr) {
106 shdr.sh_size = Elf_Ehdr::size(ei_class);
107 }
108
Elf(std::ifstream & file)109 Elf::Elf(std::ifstream& file) {
110 if (!file.is_open()) throw std::runtime_error("Error opening file");
111
112 file.exceptions(std::ifstream::eofbit | std::ifstream::failbit |
113 std::ifstream::badbit);
114 // Read ELF magic number and identification information
115 unsigned char e_ident[EI_VERSION];
116 file.seekg(0);
117 file.read((char*)e_ident, sizeof(e_ident));
118 file.seekg(0);
119 ehdr = new Elf_Ehdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
120
121 // ELFOSABI_LINUX is kept unsupported because I haven't looked whether
122 // STB_GNU_UNIQUE or STT_GNU_IFUNC would need special casing.
123 if ((ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE) &&
124 (ehdr->e_ident[EI_ABIVERSION] != 0))
125 throw std::runtime_error("unsupported ELF ABI");
126
127 if (ehdr->e_version != 1) throw std::runtime_error("unsupported ELF version");
128
129 // Sanity checks
130 if (ehdr->e_shnum == 0)
131 throw std::runtime_error("sstripped ELF files aren't supported");
132
133 if (ehdr->e_ehsize != Elf_Ehdr::size(e_ident[EI_CLASS]))
134 throw std::runtime_error(
135 "unsupported ELF inconsistency: ehdr.e_ehsize != sizeof(ehdr)");
136
137 if (ehdr->e_shentsize != Elf_Shdr::size(e_ident[EI_CLASS]))
138 throw std::runtime_error(
139 "unsupported ELF inconsistency: ehdr.e_shentsize != sizeof(shdr)");
140
141 if (ehdr->e_phnum == 0) {
142 if (ehdr->e_phoff != 0)
143 throw std::runtime_error(
144 "unsupported ELF inconsistency: e_phnum == 0 && e_phoff != 0");
145 if (ehdr->e_phentsize != 0)
146 throw std::runtime_error(
147 "unsupported ELF inconsistency: e_phnum == 0 && e_phentsize != 0");
148 } else if (ehdr->e_phoff != ehdr->e_ehsize)
149 throw std::runtime_error(
150 "unsupported ELF inconsistency: ehdr->e_phoff != ehdr->e_ehsize");
151 else if (ehdr->e_phentsize != Elf_Phdr::size(e_ident[EI_CLASS]))
152 throw std::runtime_error(
153 "unsupported ELF inconsistency: ehdr->e_phentsize != sizeof(phdr)");
154
155 // Read section headers
156 Elf_Shdr** shdr = new Elf_Shdr*[ehdr->e_shnum];
157 file.seekg(ehdr->e_shoff);
158 for (int i = 0; i < ehdr->e_shnum; i++)
159 shdr[i] = new Elf_Shdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
160
161 // Sanity check in section header for index 0
162 if ((shdr[0]->sh_name != 0) || (shdr[0]->sh_type != SHT_NULL) ||
163 (shdr[0]->sh_flags != 0) || (shdr[0]->sh_addr != 0) ||
164 (shdr[0]->sh_offset != 0) || (shdr[0]->sh_size != 0) ||
165 (shdr[0]->sh_link != SHN_UNDEF) || (shdr[0]->sh_info != 0) ||
166 (shdr[0]->sh_addralign != 0) || (shdr[0]->sh_entsize != 0))
167 throw std::runtime_error(
168 "Section header for index 0 contains unsupported values");
169
170 if ((shdr[ehdr->e_shstrndx]->sh_link != 0) ||
171 (shdr[ehdr->e_shstrndx]->sh_info != 0))
172 throw std::runtime_error(
173 "unsupported ELF content: string table with sh_link != 0 || sh_info != "
174 "0");
175
176 // Store these temporarily
177 tmp_shdr = shdr;
178 tmp_file = &file;
179
180 // Fill sections list
181 sections = new ElfSection*[ehdr->e_shnum];
182 for (int i = 0; i < ehdr->e_shnum; i++) sections[i] = nullptr;
183 for (int i = 1; i < ehdr->e_shnum; i++) {
184 // The .dynamic section is going to have references to other sections,
185 // so it's better to start with that one and recursively initialize those
186 // other sections first, to avoid possible infinite recursion (bug 1606739).
187 if (tmp_shdr[i]->sh_type == SHT_DYNAMIC) {
188 getSection(i);
189 }
190 }
191 for (int i = 1; i < ehdr->e_shnum; i++) {
192 if (sections[i] != nullptr) continue;
193 getSection(i);
194 }
195 Elf_Shdr s;
196 s.sh_name = 0;
197 s.sh_type = SHT_NULL;
198 s.sh_flags = 0;
199 s.sh_addr = 0;
200 s.sh_offset = ehdr->e_shoff;
201 s.sh_entsize = Elf_Shdr::size(e_ident[EI_CLASS]);
202 s.sh_size = s.sh_entsize * ehdr->e_shnum;
203 s.sh_link = 0;
204 s.sh_info = 0;
205 s.sh_addralign = (e_ident[EI_CLASS] == ELFCLASS32) ? 4 : 8;
206 shdr_section = new ElfSection(s, nullptr, nullptr);
207
208 // Fake section for program headers
209 s.sh_offset = ehdr->e_phoff;
210 s.sh_addr = ehdr->e_phoff;
211 s.sh_entsize = Elf_Phdr::size(e_ident[EI_CLASS]);
212 s.sh_size = s.sh_entsize * ehdr->e_phnum;
213 phdr_section = new ElfSection(s, nullptr, nullptr);
214
215 phdr_section->insertAfter(ehdr, false);
216
217 sections[1]->insertAfter(phdr_section, false);
218 for (int i = 2; i < ehdr->e_shnum; i++) {
219 // TODO: this should be done in a better way
220 if ((shdr_section->getPrevious() == nullptr) &&
221 (shdr[i]->sh_offset > ehdr->e_shoff)) {
222 shdr_section->insertAfter(sections[i - 1], false);
223 sections[i]->insertAfter(shdr_section, false);
224 } else
225 sections[i]->insertAfter(sections[i - 1], false);
226 }
227 if (shdr_section->getPrevious() == nullptr)
228 shdr_section->insertAfter(sections[ehdr->e_shnum - 1], false);
229
230 tmp_file = nullptr;
231 tmp_shdr = nullptr;
232 for (int i = 0; i < ehdr->e_shnum; i++) delete shdr[i];
233 delete[] shdr;
234
235 eh_shstrndx = (ElfStrtab_Section*)sections[ehdr->e_shstrndx];
236
237 // Skip reading program headers if there aren't any
238 if (ehdr->e_phnum == 0) return;
239
240 bool adjusted_phdr_section = false;
241 // Read program headers
242 file.seekg(ehdr->e_phoff);
243 for (int i = 0; i < ehdr->e_phnum; i++) {
244 Elf_Phdr phdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
245 if (phdr.p_type == PT_LOAD) {
246 // Default alignment for PT_LOAD on x86-64 prevents elfhack from
247 // doing anything useful. However, the system doesn't actually
248 // require such a big alignment, so in order for elfhack to work
249 // efficiently, reduce alignment when it's originally the default
250 // one.
251 if ((ehdr->e_machine == EM_X86_64) && (phdr.p_align == 0x200000))
252 phdr.p_align = 0x1000;
253 }
254 ElfSegment* segment = new ElfSegment(&phdr);
255 // Some segments aren't entirely filled (if at all) by sections
256 // For those, we use fake sections
257 if ((phdr.p_type == PT_LOAD) && (phdr.p_offset == 0)) {
258 // Use a fake section for ehdr and phdr
259 ehdr->getShdr().sh_addr = phdr.p_vaddr;
260 if (!adjusted_phdr_section) {
261 phdr_section->getShdr().sh_addr += phdr.p_vaddr;
262 adjusted_phdr_section = true;
263 }
264 segment->addSection(ehdr);
265 segment->addSection(phdr_section);
266 }
267 if (phdr.p_type == PT_PHDR) {
268 if (!adjusted_phdr_section) {
269 phdr_section->getShdr().sh_addr = phdr.p_vaddr;
270 adjusted_phdr_section = true;
271 }
272 segment->addSection(phdr_section);
273 }
274 for (int j = 1; j < ehdr->e_shnum; j++)
275 if (phdr.contains(sections[j])) segment->addSection(sections[j]);
276 // Make sure that our view of segments corresponds to the original
277 // ELF file.
278 // GNU gold likes to start some segments before the first section
279 // they contain. https://sourceware.org/bugzilla/show_bug.cgi?id=19392
280 unsigned int gold_adjustment = segment->getAddr() - phdr.p_vaddr;
281 assert(segment->getFileSize() == phdr.p_filesz - gold_adjustment);
282 // gold makes TLS segments end on an aligned virtual address, even
283 // when the underlying section ends before that, while bfd ld
284 // doesn't. It's fine if we don't keep that alignment.
285 unsigned int memsize = segment->getMemSize();
286 if (phdr.p_type == PT_TLS && memsize != phdr.p_memsz) {
287 unsigned int align = segment->getAlign();
288 memsize = (memsize + align - 1) & ~(align - 1);
289 }
290 assert(memsize == phdr.p_memsz - gold_adjustment);
291 segments.push_back(segment);
292 }
293
294 new (&eh_entry) ElfLocation(ehdr->e_entry, this);
295 }
296
~Elf()297 Elf::~Elf() {
298 for (std::vector<ElfSegment*>::iterator seg = segments.begin();
299 seg != segments.end(); seg++)
300 delete *seg;
301 delete[] sections;
302 ElfSection* section = ehdr;
303 while (section != nullptr) {
304 ElfSection* next = section->getNext();
305 delete section;
306 section = next;
307 }
308 }
309
310 // TODO: This shouldn't fail after inserting sections
getSection(int index)311 ElfSection* Elf::getSection(int index) {
312 if ((index < -1) || (index >= ehdr->e_shnum))
313 throw std::runtime_error("Section index out of bounds");
314 if (index == -1)
315 index = ehdr->e_shstrndx; // TODO: should be fixed to use the actual
316 // current number
317 // Special case: the section at index 0 is void
318 if (index == 0) return nullptr;
319 // Infinite recursion guard
320 if (sections[index] == (ElfSection*)this) return nullptr;
321 if (sections[index] == nullptr) {
322 sections[index] = (ElfSection*)this;
323 switch (tmp_shdr[index]->sh_type) {
324 case SHT_DYNAMIC:
325 sections[index] =
326 new ElfDynamic_Section(*tmp_shdr[index], tmp_file, this);
327 break;
328 case SHT_REL:
329 sections[index] =
330 new ElfRel_Section<Elf_Rel>(*tmp_shdr[index], tmp_file, this);
331 break;
332 case SHT_RELA:
333 sections[index] =
334 new ElfRel_Section<Elf_Rela>(*tmp_shdr[index], tmp_file, this);
335 break;
336 case SHT_DYNSYM:
337 case SHT_SYMTAB:
338 sections[index] =
339 new ElfSymtab_Section(*tmp_shdr[index], tmp_file, this);
340 break;
341 case SHT_STRTAB:
342 sections[index] =
343 new ElfStrtab_Section(*tmp_shdr[index], tmp_file, this);
344 break;
345 default:
346 sections[index] = new ElfSection(*tmp_shdr[index], tmp_file, this);
347 }
348 }
349 return sections[index];
350 }
351
getSectionAt(unsigned int offset)352 ElfSection* Elf::getSectionAt(unsigned int offset) {
353 for (int i = 1; i < ehdr->e_shnum; i++) {
354 ElfSection* section = getSection(i);
355 if ((section != nullptr) && (section->getFlags() & SHF_ALLOC) &&
356 !(section->getFlags() & SHF_TLS) && (offset >= section->getAddr()) &&
357 (offset < section->getAddr() + section->getSize()))
358 return section;
359 }
360 return nullptr;
361 }
362
getSegmentByType(unsigned int type,ElfSegment * last)363 ElfSegment* Elf::getSegmentByType(unsigned int type, ElfSegment* last) {
364 std::vector<ElfSegment*>::iterator seg;
365 if (last) {
366 seg = std::find(segments.begin(), segments.end(), last);
367 ++seg;
368 } else
369 seg = segments.begin();
370 for (; seg != segments.end(); seg++)
371 if ((*seg)->getType() == type) return *seg;
372 return nullptr;
373 }
374
removeSegment(ElfSegment * segment)375 void Elf::removeSegment(ElfSegment* segment) {
376 if (!segment) return;
377 std::vector<ElfSegment*>::iterator seg;
378 seg = std::find(segments.begin(), segments.end(), segment);
379 if (seg == segments.end()) return;
380 segment->clear();
381 segments.erase(seg);
382 }
383
getDynSection()384 ElfDynamic_Section* Elf::getDynSection() {
385 for (std::vector<ElfSegment*>::iterator seg = segments.begin();
386 seg != segments.end(); seg++)
387 if (((*seg)->getType() == PT_DYNAMIC) &&
388 ((*seg)->getFirstSection() != nullptr) &&
389 (*seg)->getFirstSection()->getType() == SHT_DYNAMIC)
390 return (ElfDynamic_Section*)(*seg)->getFirstSection();
391
392 return nullptr;
393 }
394
normalize()395 void Elf::normalize() {
396 // fixup section headers sh_name; TODO: that should be done by sections
397 // themselves
398 for (ElfSection* section = ehdr; section != nullptr;
399 section = section->getNext()) {
400 if (section->getIndex() == 0)
401 continue;
402 else
403 ehdr->e_shnum = section->getIndex() + 1;
404 section->getShdr().sh_name = eh_shstrndx->getStrIndex(section->getName());
405 }
406 ehdr->markDirty();
407 // Check segments consistency
408 int i = 0;
409 for (std::vector<ElfSegment*>::iterator seg = segments.begin();
410 seg != segments.end(); seg++, i++) {
411 std::list<ElfSection*>::iterator it = (*seg)->begin();
412 for (ElfSection* last = *(it++); it != (*seg)->end(); last = *(it++)) {
413 if (((*it)->getType() != SHT_NOBITS) &&
414 ((*it)->getAddr() - last->getAddr()) !=
415 ((*it)->getOffset() - last->getOffset())) {
416 throw std::runtime_error("Segments inconsistency");
417 }
418 }
419 }
420
421 ElfSegment* prevLoad = nullptr;
422 for (auto& it : segments) {
423 if (it->getType() == PT_LOAD) {
424 if (prevLoad) {
425 size_t alignedPrevEnd = (prevLoad->getAddr() + prevLoad->getMemSize() +
426 prevLoad->getAlign() - 1) &
427 ~(prevLoad->getAlign() - 1);
428 size_t alignedStart = it->getAddr() & ~(it->getAlign() - 1);
429 if (alignedPrevEnd > alignedStart) {
430 throw std::runtime_error("Segments overlap");
431 }
432 }
433 prevLoad = it;
434 }
435 }
436
437 // fixup ehdr before writing
438 if (ehdr->e_phnum != segments.size()) {
439 ehdr->e_phnum = segments.size();
440 phdr_section->getShdr().sh_size =
441 segments.size() * Elf_Phdr::size(ehdr->e_ident[EI_CLASS]);
442 phdr_section->getNext()->markDirty();
443 }
444 // fixup shdr before writing
445 if (ehdr->e_shnum != shdr_section->getSize() / shdr_section->getEntSize())
446 shdr_section->getShdr().sh_size =
447 ehdr->e_shnum * Elf_Shdr::size(ehdr->e_ident[EI_CLASS]);
448 ehdr->e_shoff = shdr_section->getOffset();
449 ehdr->e_entry = eh_entry.getValue();
450 ehdr->e_shstrndx = eh_shstrndx->getIndex();
451
452 // Check sections consistency
453 unsigned int minOffset = 0;
454 for (ElfSection* section = ehdr; section != nullptr;
455 section = section->getNext()) {
456 unsigned int offset = section->getOffset();
457 if (offset < minOffset) {
458 throw std::runtime_error("Sections overlap");
459 }
460 if (section->getType() != SHT_NOBITS) {
461 minOffset = offset + section->getSize();
462 }
463 }
464 }
465
write(std::ofstream & file)466 void Elf::write(std::ofstream& file) {
467 normalize();
468 for (ElfSection* section = ehdr; section != nullptr;
469 section = section->getNext()) {
470 file.seekp(section->getOffset());
471 if (section == phdr_section) {
472 for (std::vector<ElfSegment*>::iterator seg = segments.begin();
473 seg != segments.end(); seg++) {
474 Elf_Phdr phdr;
475 phdr.p_type = (*seg)->getType();
476 phdr.p_flags = (*seg)->getFlags();
477 phdr.p_offset = (*seg)->getOffset();
478 phdr.p_vaddr = (*seg)->getAddr();
479 phdr.p_paddr = phdr.p_vaddr + (*seg)->getVPDiff();
480 phdr.p_filesz = (*seg)->getFileSize();
481 phdr.p_memsz = (*seg)->getMemSize();
482 phdr.p_align = (*seg)->getAlign();
483 phdr.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
484 }
485 } else if (section == shdr_section) {
486 null_section.serialize(file, ehdr->e_ident[EI_CLASS],
487 ehdr->e_ident[EI_DATA]);
488 for (ElfSection* sec = ehdr; sec != nullptr; sec = sec->getNext()) {
489 if (sec->getType() != SHT_NULL)
490 sec->getShdr().serialize(file, ehdr->e_ident[EI_CLASS],
491 ehdr->e_ident[EI_DATA]);
492 }
493 } else
494 section->serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
495 }
496 }
497
ElfSection(Elf_Shdr & s,std::ifstream * file,Elf * parent)498 ElfSection::ElfSection(Elf_Shdr& s, std::ifstream* file, Elf* parent)
499 : shdr(s),
500 link(shdr.sh_link == SHN_UNDEF ? nullptr
501 : parent->getSection(shdr.sh_link)),
502 next(nullptr),
503 previous(nullptr),
504 index(-1) {
505 if ((file == nullptr) || (shdr.sh_type == SHT_NULL) ||
506 (shdr.sh_type == SHT_NOBITS))
507 data = nullptr;
508 else {
509 data = static_cast<char*>(malloc(shdr.sh_size));
510 if (!data) {
511 throw std::runtime_error("Could not malloc ElfSection data");
512 }
513 auto pos = file->tellg();
514 file->seekg(shdr.sh_offset);
515 file->read(data, shdr.sh_size);
516 file->seekg(pos);
517 }
518 if (shdr.sh_name == 0)
519 name = nullptr;
520 else {
521 ElfStrtab_Section* strtab = (ElfStrtab_Section*)parent->getSection(-1);
522 // Special case (see elfgeneric.cpp): if strtab is nullptr, the
523 // section being created is the strtab.
524 if (strtab == nullptr)
525 name = &data[shdr.sh_name];
526 else
527 name = strtab->getStr(shdr.sh_name);
528 }
529 // Only SHT_REL/SHT_RELA sections use sh_info to store a section
530 // number.
531 if ((shdr.sh_type == SHT_REL) || (shdr.sh_type == SHT_RELA))
532 info.section = shdr.sh_info ? parent->getSection(shdr.sh_info) : nullptr;
533 else
534 info.index = shdr.sh_info;
535 }
536
getAddr()537 unsigned int ElfSection::getAddr() {
538 if (shdr.sh_addr != (Elf64_Addr)-1) return shdr.sh_addr;
539
540 // It should be safe to adjust sh_addr for all allocated sections that
541 // are neither SHT_NOBITS nor SHT_PROGBITS
542 if ((previous != nullptr) && isRelocatable()) {
543 unsigned int addr = previous->getAddr();
544 if (previous->getType() != SHT_NOBITS) addr += previous->getSize();
545
546 if (addr & (getAddrAlign() - 1)) addr = (addr | (getAddrAlign() - 1)) + 1;
547
548 return (shdr.sh_addr = addr);
549 }
550 return shdr.sh_addr;
551 }
552
getOffset()553 unsigned int ElfSection::getOffset() {
554 if (shdr.sh_offset != (Elf64_Off)-1) return shdr.sh_offset;
555
556 if (previous == nullptr) return (shdr.sh_offset = 0);
557
558 unsigned int offset = previous->getOffset();
559
560 ElfSegment* ptload = getSegmentByType(PT_LOAD);
561 ElfSegment* prev_ptload = previous->getSegmentByType(PT_LOAD);
562
563 if (ptload && (ptload == prev_ptload)) {
564 offset += getAddr() - previous->getAddr();
565 return (shdr.sh_offset = offset);
566 }
567
568 if (previous->getType() != SHT_NOBITS) offset += previous->getSize();
569
570 Elf32_Word align = 0x1000;
571 for (std::vector<ElfSegment*>::iterator seg = segments.begin();
572 seg != segments.end(); seg++)
573 align = std::max(align, (*seg)->getAlign());
574
575 Elf32_Word mask = align - 1;
576 // SHF_TLS is used for .tbss which is some kind of special case.
577 if (((getType() != SHT_NOBITS) || (getFlags() & SHF_TLS)) &&
578 (getFlags() & SHF_ALLOC)) {
579 if ((getAddr() & mask) < (offset & mask))
580 offset = (offset | mask) + (getAddr() & mask) + 1;
581 else
582 offset = (offset & ~mask) + (getAddr() & mask);
583 }
584 if ((getType() != SHT_NOBITS) && (offset & (getAddrAlign() - 1)))
585 offset = (offset | (getAddrAlign() - 1)) + 1;
586
587 return (shdr.sh_offset = offset);
588 }
589
getIndex()590 int ElfSection::getIndex() {
591 if (index != -1) return index;
592 if (getType() == SHT_NULL) return (index = 0);
593 ElfSection* reference;
594 for (reference = previous;
595 (reference != nullptr) && (reference->getType() == SHT_NULL);
596 reference = reference->getPrevious())
597 ;
598 if (reference == nullptr) return (index = 1);
599 return (index = reference->getIndex() + 1);
600 }
601
getShdr()602 Elf_Shdr& ElfSection::getShdr() {
603 getOffset();
604 if (shdr.sh_link == (Elf64_Word)-1)
605 shdr.sh_link = getLink() ? getLink()->getIndex() : 0;
606 if (shdr.sh_info == (Elf64_Word)-1)
607 shdr.sh_info = ((getType() == SHT_REL) || (getType() == SHT_RELA))
608 ? (getInfo().section ? getInfo().section->getIndex() : 0)
609 : getInfo().index;
610
611 return shdr;
612 }
613
ElfSegment(Elf_Phdr * phdr)614 ElfSegment::ElfSegment(Elf_Phdr* phdr)
615 : type(phdr->p_type),
616 v_p_diff(phdr->p_paddr - phdr->p_vaddr),
617 flags(phdr->p_flags),
618 align(phdr->p_align),
619 vaddr(phdr->p_vaddr),
620 filesz(phdr->p_filesz),
621 memsz(phdr->p_memsz) {}
622
addSection(ElfSection * section)623 void ElfSegment::addSection(ElfSection* section) {
624 // Make sure all sections in PT_GNU_RELRO won't be moved by elfhack
625 assert(!((type == PT_GNU_RELRO) && (section->isRelocatable())));
626
627 // TODO: Check overlapping sections
628 std::list<ElfSection*>::iterator i;
629 for (i = sections.begin(); i != sections.end(); ++i)
630 if ((*i)->getAddr() > section->getAddr()) break;
631 sections.insert(i, section);
632 section->addToSegment(this);
633 }
634
removeSection(ElfSection * section)635 void ElfSegment::removeSection(ElfSection* section) {
636 sections.remove(section);
637 section->removeFromSegment(this);
638 }
639
getFileSize()640 unsigned int ElfSegment::getFileSize() {
641 if (type == PT_GNU_RELRO) return filesz;
642
643 if (sections.empty()) return 0;
644 // Search the last section that is not SHT_NOBITS
645 std::list<ElfSection*>::reverse_iterator i;
646 for (i = sections.rbegin();
647 (i != sections.rend()) && ((*i)->getType() == SHT_NOBITS); ++i)
648 ;
649 // All sections are SHT_NOBITS
650 if (i == sections.rend()) return 0;
651
652 unsigned int end = (*i)->getAddr() + (*i)->getSize();
653
654 return end - sections.front()->getAddr();
655 }
656
getMemSize()657 unsigned int ElfSegment::getMemSize() {
658 if (type == PT_GNU_RELRO) return memsz;
659
660 if (sections.empty()) return 0;
661
662 unsigned int end = sections.back()->getAddr() + sections.back()->getSize();
663
664 return end - sections.front()->getAddr();
665 }
666
getOffset()667 unsigned int ElfSegment::getOffset() {
668 if ((type == PT_GNU_RELRO) && !sections.empty() &&
669 (sections.front()->getAddr() != vaddr))
670 throw std::runtime_error(
671 "PT_GNU_RELRO segment doesn't start on a section start");
672
673 return sections.empty() ? 0 : sections.front()->getOffset();
674 }
675
getAddr()676 unsigned int ElfSegment::getAddr() {
677 if ((type == PT_GNU_RELRO) && !sections.empty() &&
678 (sections.front()->getAddr() != vaddr))
679 throw std::runtime_error(
680 "PT_GNU_RELRO segment doesn't start on a section start");
681
682 return sections.empty() ? 0 : sections.front()->getAddr();
683 }
684
clear()685 void ElfSegment::clear() {
686 for (std::list<ElfSection*>::iterator i = sections.begin();
687 i != sections.end(); ++i)
688 (*i)->removeFromSegment(this);
689 sections.clear();
690 }
691
getValueForType(unsigned int tag)692 ElfValue* ElfDynamic_Section::getValueForType(unsigned int tag) {
693 for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++)
694 if (dyns[i].tag == tag) return dyns[i].value;
695
696 return nullptr;
697 }
698
getSectionForType(unsigned int tag)699 ElfSection* ElfDynamic_Section::getSectionForType(unsigned int tag) {
700 ElfValue* value = getValueForType(tag);
701 return value ? value->getSection() : nullptr;
702 }
703
setValueForType(unsigned int tag,ElfValue * val)704 bool ElfDynamic_Section::setValueForType(unsigned int tag, ElfValue* val) {
705 unsigned int i;
706 unsigned int shnum = shdr.sh_size / shdr.sh_entsize;
707 for (i = 0; (i < shnum) && (dyns[i].tag != DT_NULL); i++)
708 if (dyns[i].tag == tag) {
709 delete dyns[i].value;
710 dyns[i].value = val;
711 return true;
712 }
713 // If we get here, this means we didn't match for the given tag
714 // Most of the time, there are a few DT_NULL entries, that we can
715 // use to add our value, but if we are on the last entry, we can't.
716 if (i >= shnum - 1) return false;
717
718 dyns[i].tag = tag;
719 dyns[i].value = val;
720 return true;
721 }
722
ElfDynamic_Section(Elf_Shdr & s,std::ifstream * file,Elf * parent)723 ElfDynamic_Section::ElfDynamic_Section(Elf_Shdr& s, std::ifstream* file,
724 Elf* parent)
725 : ElfSection(s, file, parent) {
726 auto pos = file->tellg();
727 dyns.resize(s.sh_size / s.sh_entsize);
728 file->seekg(shdr.sh_offset);
729 // Here we assume tags refer to only one section (e.g. DT_RELSZ accounts
730 // for .rel.dyn size)
731 for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) {
732 Elf_Dyn dyn(*file, parent->getClass(), parent->getData());
733 dyns[i].tag = dyn.d_tag;
734 switch (dyn.d_tag) {
735 case DT_NULL:
736 case DT_SYMBOLIC:
737 case DT_TEXTREL:
738 case DT_BIND_NOW:
739 dyns[i].value = new ElfValue();
740 break;
741 case DT_NEEDED:
742 case DT_SONAME:
743 case DT_RPATH:
744 case DT_PLTREL:
745 case DT_RUNPATH:
746 case DT_FLAGS:
747 case DT_RELACOUNT:
748 case DT_RELCOUNT:
749 case DT_VERDEFNUM:
750 case DT_VERNEEDNUM:
751 dyns[i].value = new ElfPlainValue(dyn.d_un.d_val);
752 break;
753 case DT_PLTGOT:
754 case DT_HASH:
755 case DT_STRTAB:
756 case DT_SYMTAB:
757 case DT_RELA:
758 case DT_INIT:
759 case DT_FINI:
760 case DT_REL:
761 case DT_JMPREL:
762 case DT_INIT_ARRAY:
763 case DT_FINI_ARRAY:
764 case DT_GNU_HASH:
765 case DT_VERSYM:
766 case DT_VERNEED:
767 case DT_VERDEF:
768 dyns[i].value = new ElfLocation(dyn.d_un.d_ptr, parent);
769 break;
770 default:
771 dyns[i].value = nullptr;
772 }
773 }
774 // Another loop to get the section sizes
775 for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++)
776 switch (dyns[i].tag) {
777 case DT_PLTRELSZ:
778 dyns[i].value = new ElfSize(getSectionForType(DT_JMPREL));
779 break;
780 case DT_RELASZ:
781 dyns[i].value = new ElfSize(getSectionForType(DT_RELA));
782 break;
783 case DT_STRSZ:
784 dyns[i].value = new ElfSize(getSectionForType(DT_STRTAB));
785 break;
786 case DT_RELSZ:
787 dyns[i].value = new ElfSize(getSectionForType(DT_REL));
788 break;
789 case DT_INIT_ARRAYSZ:
790 dyns[i].value = new ElfSize(getSectionForType(DT_INIT_ARRAY));
791 break;
792 case DT_FINI_ARRAYSZ:
793 dyns[i].value = new ElfSize(getSectionForType(DT_FINI_ARRAY));
794 break;
795 case DT_RELAENT:
796 dyns[i].value = new ElfEntSize(getSectionForType(DT_RELA));
797 break;
798 case DT_SYMENT:
799 dyns[i].value = new ElfEntSize(getSectionForType(DT_SYMTAB));
800 break;
801 case DT_RELENT:
802 dyns[i].value = new ElfEntSize(getSectionForType(DT_REL));
803 break;
804 }
805
806 file->seekg(pos);
807 }
808
~ElfDynamic_Section()809 ElfDynamic_Section::~ElfDynamic_Section() {
810 for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++)
811 delete dyns[i].value;
812 }
813
serialize(std::ofstream & file,unsigned char ei_class,unsigned char ei_data)814 void ElfDynamic_Section::serialize(std::ofstream& file, unsigned char ei_class,
815 unsigned char ei_data) {
816 for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
817 Elf_Dyn dyn;
818 dyn.d_tag = dyns[i].tag;
819 dyn.d_un.d_val = (dyns[i].value != nullptr) ? dyns[i].value->getValue() : 0;
820 dyn.serialize(file, ei_class, ei_data);
821 }
822 }
823
ElfSymtab_Section(Elf_Shdr & s,std::ifstream * file,Elf * parent)824 ElfSymtab_Section::ElfSymtab_Section(Elf_Shdr& s, std::ifstream* file,
825 Elf* parent)
826 : ElfSection(s, file, parent) {
827 auto pos = file->tellg();
828 syms.resize(s.sh_size / s.sh_entsize);
829 ElfStrtab_Section* strtab = (ElfStrtab_Section*)getLink();
830 file->seekg(shdr.sh_offset);
831 for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
832 Elf_Sym sym(*file, parent->getClass(), parent->getData());
833 syms[i].name = strtab->getStr(sym.st_name);
834 syms[i].info = sym.st_info;
835 syms[i].other = sym.st_other;
836 ElfSection* section =
837 (sym.st_shndx == SHN_ABS) ? nullptr : parent->getSection(sym.st_shndx);
838 new (&syms[i].value)
839 ElfLocation(section, sym.st_value, ElfLocation::ABSOLUTE);
840 syms[i].size = sym.st_size;
841 syms[i].defined = (sym.st_shndx != SHN_UNDEF);
842 }
843 file->seekg(pos);
844 }
845
serialize(std::ofstream & file,unsigned char ei_class,unsigned char ei_data)846 void ElfSymtab_Section::serialize(std::ofstream& file, unsigned char ei_class,
847 unsigned char ei_data) {
848 ElfStrtab_Section* strtab = (ElfStrtab_Section*)getLink();
849 for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
850 Elf_Sym sym;
851 sym.st_name = strtab->getStrIndex(syms[i].name);
852 sym.st_info = syms[i].info;
853 sym.st_other = syms[i].other;
854 sym.st_value = syms[i].value.getValue();
855 ElfSection* section = syms[i].value.getSection();
856 if (syms[i].defined)
857 sym.st_shndx = section ? section->getIndex() : SHN_ABS;
858 else
859 sym.st_shndx = SHN_UNDEF;
860 sym.st_size = syms[i].size;
861 sym.serialize(file, ei_class, ei_data);
862 }
863 }
864
lookup(const char * name,unsigned int type_filter)865 Elf_SymValue* ElfSymtab_Section::lookup(const char* name,
866 unsigned int type_filter) {
867 for (std::vector<Elf_SymValue>::iterator sym = syms.begin();
868 sym != syms.end(); sym++) {
869 if ((type_filter & (1 << ELF32_ST_TYPE(sym->info))) &&
870 (strcmp(sym->name, name) == 0)) {
871 return &*sym;
872 }
873 }
874 return nullptr;
875 }
876
getStr(unsigned int index)877 const char* ElfStrtab_Section::getStr(unsigned int index) {
878 for (std::vector<table_storage>::iterator t = table.begin(); t != table.end();
879 t++) {
880 if (index < t->used) return t->buf + index;
881 index -= t->used;
882 }
883 assert(1 == 0);
884 return nullptr;
885 }
886
getStr(const char * string)887 const char* ElfStrtab_Section::getStr(const char* string) {
888 if (string == nullptr) return nullptr;
889
890 // If the given string is within the section, return it
891 for (std::vector<table_storage>::iterator t = table.begin(); t != table.end();
892 t++)
893 if ((string >= t->buf) && (string < t->buf + t->used)) return string;
894
895 // TODO: should scan in the section to find an existing string
896
897 // If not, we need to allocate the string in the section
898 size_t len = strlen(string) + 1;
899
900 if (table.back().size - table.back().used < len)
901 table.resize(table.size() + 1);
902
903 char* alloc_str = table.back().buf + table.back().used;
904 memcpy(alloc_str, string, len);
905 table.back().used += len;
906
907 shdr.sh_size += len;
908 markDirty();
909
910 return alloc_str;
911 }
912
getStrIndex(const char * string)913 unsigned int ElfStrtab_Section::getStrIndex(const char* string) {
914 if (string == nullptr) return 0;
915
916 unsigned int index = 0;
917 string = getStr(string);
918 for (std::vector<table_storage>::iterator t = table.begin(); t != table.end();
919 t++) {
920 if ((string >= t->buf) && (string < t->buf + t->used))
921 return index + (string - t->buf);
922 index += t->used;
923 }
924
925 assert(1 == 0);
926 return 0;
927 }
928
serialize(std::ofstream & file,unsigned char ei_class,unsigned char ei_data)929 void ElfStrtab_Section::serialize(std::ofstream& file, unsigned char ei_class,
930 unsigned char ei_data) {
931 file.seekp(getOffset());
932 for (std::vector<table_storage>::iterator t = table.begin(); t != table.end();
933 t++)
934 file.write(t->buf, t->used);
935 }
936