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