OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "courgette/disassembler_elf_32.h" | 5 #include "courgette/disassembler_elf_32.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <iterator> |
8 #include <utility> | 9 #include <utility> |
9 | 10 |
10 #include "base/logging.h" | 11 #include "base/logging.h" |
11 #include "courgette/assembly_program.h" | 12 #include "courgette/assembly_program.h" |
12 #include "courgette/courgette.h" | 13 #include "courgette/courgette.h" |
13 | 14 |
14 namespace courgette { | 15 namespace courgette { |
15 | 16 |
16 namespace { | 17 namespace { |
17 | 18 |
18 // Sorts |section_headers| by file offset and stores the resulting permutation | 19 // Sorts |section_headers| by file offset and stores the resulting permutation |
19 // of section ids in |order|. | 20 // of section ids in |order|. |
20 std::vector<Elf32_Half> GetSectionHeaderFileOffsetOrder( | 21 std::vector<Elf32_Half> GetSectionHeaderFileOffsetOrder( |
21 const std::vector<Elf32_Shdr>& section_headers) { | 22 const std::vector<Elf32_Shdr>& section_headers) { |
22 size_t size = section_headers.size(); | 23 size_t size = section_headers.size(); |
23 std::vector<Elf32_Half> order(size); | 24 std::vector<Elf32_Half> order(size); |
24 for (size_t i = 0; i < size; ++i) | 25 for (size_t i = 0; i < size; ++i) |
25 order[i] = static_cast<Elf32_Half>(i); | 26 order[i] = static_cast<Elf32_Half>(i); |
26 | 27 |
27 auto comp = [&](int idx1, int idx2) { | 28 auto comp = [&](int idx1, int idx2) { |
28 return section_headers[idx1].sh_offset < section_headers[idx2].sh_offset; | 29 return section_headers[idx1].sh_offset < section_headers[idx2].sh_offset; |
29 }; | 30 }; |
30 std::stable_sort(order.begin(), order.end(), comp); | 31 std::stable_sort(order.begin(), order.end(), comp); |
31 return order; | 32 return order; |
32 } | 33 } |
33 | 34 |
34 } // namespace | 35 } // namespace |
35 | 36 |
| 37 DisassemblerElf32::Elf32RvaVisitor_Rel32::Elf32RvaVisitor_Rel32( |
| 38 const std::vector<std::unique_ptr<TypedRVA>>& rva_locations) |
| 39 : VectorRvaVisitor<std::unique_ptr<TypedRVA>>(rva_locations) { |
| 40 } |
| 41 |
| 42 RVA DisassemblerElf32::Elf32RvaVisitor_Rel32::Get() const { |
| 43 return (*it_)->rva() + (*it_)->relative_target(); |
| 44 } |
| 45 |
36 DisassemblerElf32::DisassemblerElf32(const void* start, size_t length) | 46 DisassemblerElf32::DisassemblerElf32(const void* start, size_t length) |
37 : Disassembler(start, length), | 47 : Disassembler(start, length), |
38 header_(nullptr), | 48 header_(nullptr), |
39 section_header_table_size_(0), | 49 section_header_table_size_(0), |
40 program_header_table_(nullptr), | 50 program_header_table_(nullptr), |
41 program_header_table_size_(0), | 51 program_header_table_size_(0), |
42 default_string_section_(nullptr) { | 52 default_string_section_(nullptr) { |
43 } | 53 } |
44 | 54 |
45 RVA DisassemblerElf32::FileOffsetToRVA(FileOffset offset) const { | 55 RVA DisassemblerElf32::FileOffsetToRVA(FileOffset offset) const { |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 bool DisassemblerElf32::Disassemble(AssemblyProgram* target) { | 167 bool DisassemblerElf32::Disassemble(AssemblyProgram* target) { |
158 if (!ok()) | 168 if (!ok()) |
159 return false; | 169 return false; |
160 | 170 |
161 // The Image Base is always 0 for ELF Executables | 171 // The Image Base is always 0 for ELF Executables |
162 target->set_image_base(0); | 172 target->set_image_base(0); |
163 | 173 |
164 if (!ParseAbs32Relocs()) | 174 if (!ParseAbs32Relocs()) |
165 return false; | 175 return false; |
166 | 176 |
167 if (!ParseRel32RelocsFromSections()) | 177 if (!ParseRel32RelocsFromSections()) // Does not sort rel32 locations. |
168 return false; | 178 return false; |
169 | 179 |
| 180 PrecomputeLabels(target); |
| 181 RemoveUnusedRel32Locations(target); |
| 182 |
170 if (!ParseFile(target)) | 183 if (!ParseFile(target)) |
171 return false; | 184 return false; |
172 | 185 |
| 186 // Finally sort rel32 locations. |
173 std::sort(rel32_locations_.begin(), | 187 std::sort(rel32_locations_.begin(), |
174 rel32_locations_.end(), | 188 rel32_locations_.end(), |
175 TypedRVA::IsLessThanByRVA); | 189 TypedRVA::IsLessThanByRVA); |
176 DCHECK(rel32_locations_.empty() || | 190 DCHECK(rel32_locations_.empty() || |
177 rel32_locations_.back()->rva() != kUnassignedRVA); | 191 rel32_locations_.back()->rva() != kUnassignedRVA); |
178 | 192 |
179 target->DefaultAssignIndexes(); | 193 target->DefaultAssignIndexes(); |
180 return true; | 194 return true; |
181 } | 195 } |
182 | 196 |
| 197 CheckBool DisassemblerElf32::IsValidTargetRVA(RVA rva) const { |
| 198 if (rva == kUnassignedRVA) |
| 199 return false; |
| 200 |
| 201 // |rva| is valid if it's contained in any program segment. |
| 202 for (Elf32_Half segment_id = 0; segment_id < ProgramSegmentHeaderCount(); |
| 203 ++segment_id) { |
| 204 const Elf32_Phdr* segment_header = ProgramSegmentHeader(segment_id); |
| 205 |
| 206 if (segment_header->p_type != PT_LOAD) |
| 207 continue; |
| 208 |
| 209 Elf32_Addr begin = segment_header->p_vaddr; |
| 210 Elf32_Addr end = segment_header->p_vaddr + segment_header->p_memsz; |
| 211 |
| 212 if (rva >= begin && rva < end) |
| 213 return true; |
| 214 } |
| 215 |
| 216 return false; |
| 217 } |
| 218 |
183 bool DisassemblerElf32::UpdateLength() { | 219 bool DisassemblerElf32::UpdateLength() { |
184 Elf32_Off result = 0; | 220 Elf32_Off result = 0; |
185 | 221 |
186 // Find the end of the last section | 222 // Find the end of the last section |
187 for (Elf32_Half section_id = 0; section_id < SectionHeaderCount(); | 223 for (Elf32_Half section_id = 0; section_id < SectionHeaderCount(); |
188 ++section_id) { | 224 ++section_id) { |
189 const Elf32_Shdr* section_header = SectionHeader(section_id); | 225 const Elf32_Shdr* section_header = SectionHeader(section_id); |
190 | 226 |
191 if (section_header->sh_type == SHT_NOBITS) | 227 if (section_header->sh_type == SHT_NOBITS) |
192 continue; | 228 continue; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 name->clear(); | 267 name->clear(); |
232 } else { | 268 } else { |
233 if (string_pos >= default_string_section_size_) | 269 if (string_pos >= default_string_section_size_) |
234 return false; | 270 return false; |
235 // Safe because string section must terminate with null. | 271 // Safe because string section must terminate with null. |
236 *name = default_string_section_ + string_pos; | 272 *name = default_string_section_ + string_pos; |
237 } | 273 } |
238 return true; | 274 return true; |
239 } | 275 } |
240 | 276 |
241 CheckBool DisassemblerElf32::IsValidTargetRVA(RVA rva) const { | |
242 if (rva == kUnassignedRVA) | |
243 return false; | |
244 | |
245 // It's valid if it's contained in any program segment | |
246 for (Elf32_Half segment_id = 0; segment_id < ProgramSegmentHeaderCount(); | |
247 ++segment_id) { | |
248 const Elf32_Phdr* segment_header = ProgramSegmentHeader(segment_id); | |
249 | |
250 if (segment_header->p_type != PT_LOAD) | |
251 continue; | |
252 | |
253 Elf32_Addr begin = segment_header->p_vaddr; | |
254 Elf32_Addr end = segment_header->p_vaddr + segment_header->p_memsz; | |
255 | |
256 if (rva >= begin && rva < end) | |
257 return true; | |
258 } | |
259 | |
260 return false; | |
261 } | |
262 | |
263 CheckBool DisassemblerElf32::RVAsToFileOffsets( | 277 CheckBool DisassemblerElf32::RVAsToFileOffsets( |
264 const std::vector<RVA>& rvas, | 278 const std::vector<RVA>& rvas, |
265 std::vector<FileOffset>* file_offsets) { | 279 std::vector<FileOffset>* file_offsets) { |
266 file_offsets->clear(); | 280 file_offsets->clear(); |
| 281 file_offsets->reserve(rvas.size()); |
267 for (RVA rva : rvas) { | 282 for (RVA rva : rvas) { |
268 FileOffset file_offset = RVAToFileOffset(rva); | 283 FileOffset file_offset = RVAToFileOffset(rva); |
269 if (file_offset == kNoFileOffset) | 284 if (file_offset == kNoFileOffset) |
270 return false; | 285 return false; |
271 file_offsets->push_back(file_offset); | 286 file_offsets->push_back(file_offset); |
272 } | 287 } |
273 return true; | 288 return true; |
274 } | 289 } |
275 | 290 |
276 CheckBool DisassemblerElf32::RVAsToFileOffsets( | 291 CheckBool DisassemblerElf32::RVAsToFileOffsets( |
277 std::vector<std::unique_ptr<TypedRVA>>* typed_rvas) { | 292 std::vector<std::unique_ptr<TypedRVA>>* typed_rvas) { |
278 for (auto& typed_rva : *typed_rvas) { | 293 for (auto& typed_rva : *typed_rvas) { |
279 FileOffset file_offset = RVAToFileOffset(typed_rva->rva()); | 294 FileOffset file_offset = RVAToFileOffset(typed_rva->rva()); |
280 if (file_offset == kNoFileOffset) | 295 if (file_offset == kNoFileOffset) |
281 return false; | 296 return false; |
282 typed_rva->set_file_offset(file_offset); | 297 typed_rva->set_file_offset(file_offset); |
283 } | 298 } |
284 return true; | 299 return true; |
285 } | 300 } |
286 | 301 |
| 302 RvaVisitor* DisassemblerElf32::CreateAbs32TargetRvaVisitor() { |
| 303 return new RvaVisitor_Abs32(abs32_locations_, *this); |
| 304 } |
| 305 |
| 306 RvaVisitor* DisassemblerElf32::CreateRel32TargetRvaVisitor() { |
| 307 return new Elf32RvaVisitor_Rel32(rel32_locations_); |
| 308 } |
| 309 |
| 310 void DisassemblerElf32::RemoveUnusedRel32Locations(AssemblyProgram* program) { |
| 311 auto tail_it = rel32_locations_.begin(); |
| 312 for (auto head_it = rel32_locations_.begin(); |
| 313 head_it != rel32_locations_.end(); ++head_it) { |
| 314 RVA target_rva = (*head_it)->rva() + (*head_it)->relative_target(); |
| 315 if (program->FindRel32Label(target_rva) == nullptr) { |
| 316 // If address does not match a Label (because it was removed), deallocate. |
| 317 (*head_it).reset(nullptr); |
| 318 } else { |
| 319 // Else squeeze nullptr to end to compactify. |
| 320 if (tail_it != head_it) |
| 321 (*tail_it).swap(*head_it); |
| 322 ++tail_it; |
| 323 } |
| 324 } |
| 325 rel32_locations_.resize(std::distance(rel32_locations_.begin(), tail_it)); |
| 326 } |
| 327 |
287 CheckBool DisassemblerElf32::ParseFile(AssemblyProgram* program) { | 328 CheckBool DisassemblerElf32::ParseFile(AssemblyProgram* program) { |
288 // Walk all the bytes in the file, whether or not in a section. | 329 // Walk all the bytes in the file, whether or not in a section. |
289 FileOffset file_offset = 0; | 330 FileOffset file_offset = 0; |
290 | 331 |
291 std::vector<FileOffset> abs_offsets; | 332 std::vector<FileOffset> abs_offsets; |
292 | 333 |
293 // File parsing follows file offset order, and we visit abs32 and rel32 | 334 // File parsing follows file offset order, and we visit abs32 and rel32 |
294 // locations in lockstep. Therefore we need to extract and sort file offsets | 335 // locations in lockstep. Therefore we need to extract and sort file offsets |
295 // of all abs32 and rel32 locations. | 336 // of all abs32 and rel32 locations. |
296 if (!RVAsToFileOffsets(abs32_locations_, &abs_offsets)) | 337 if (!RVAsToFileOffsets(abs32_locations_, &abs_offsets)) |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 | 459 |
419 file_offset = next_relocation; | 460 file_offset = next_relocation; |
420 continue; | 461 continue; |
421 } | 462 } |
422 | 463 |
423 if (*current_abs_offset != end_abs_offset && | 464 if (*current_abs_offset != end_abs_offset && |
424 file_offset == **current_abs_offset) { | 465 file_offset == **current_abs_offset) { |
425 RVA target_rva = PointerToTargetRVA(FileOffsetToPointer(file_offset)); | 466 RVA target_rva = PointerToTargetRVA(FileOffsetToPointer(file_offset)); |
426 DCHECK_NE(kNoRVA, target_rva); | 467 DCHECK_NE(kNoRVA, target_rva); |
427 | 468 |
428 if (!program->EmitAbs32(program->FindOrMakeAbs32Label(target_rva))) | 469 Label* label = program->FindAbs32Label(target_rva); |
| 470 CHECK(label); |
| 471 if (!program->EmitAbs32(label)) |
429 return false; | 472 return false; |
430 file_offset += sizeof(RVA); | 473 file_offset += sizeof(RVA); |
431 ++(*current_abs_offset); | 474 ++(*current_abs_offset); |
432 continue; | 475 continue; |
433 } | 476 } |
434 | 477 |
435 if (*current_rel != end_rel && | 478 if (*current_rel != end_rel && |
436 file_offset == (**current_rel)->file_offset()) { | 479 file_offset == (**current_rel)->file_offset()) { |
437 uint32_t relative_target = (**current_rel)->relative_target(); | 480 uint32_t relative_target = (**current_rel)->relative_target(); |
| 481 CHECK_EQ(RVA(origin + (file_offset - origin_offset)), |
| 482 (**current_rel)->rva()); |
438 // This cast is for 64 bit systems, and is only safe because we | 483 // This cast is for 64 bit systems, and is only safe because we |
439 // are working on 32 bit executables. | 484 // are working on 32 bit executables. |
440 RVA target_rva = (RVA)(origin + (file_offset - origin_offset) + | 485 RVA target_rva = (RVA)(origin + (file_offset - origin_offset) + |
441 relative_target); | 486 relative_target); |
442 | 487 |
443 if (!(**current_rel)->EmitInstruction(program, target_rva)) | 488 Label* label = program->FindRel32Label(target_rva); |
| 489 CHECK(label); |
| 490 |
| 491 if (!(**current_rel)->EmitInstruction(program, label)) |
444 return false; | 492 return false; |
445 file_offset += (**current_rel)->op_size(); | 493 file_offset += (**current_rel)->op_size(); |
446 ++(*current_rel); | 494 ++(*current_rel); |
447 continue; | 495 continue; |
448 } | 496 } |
449 } | 497 } |
450 | 498 |
451 // Rest of the section (if any) | 499 // Rest of the section (if any) |
452 return ParseSimpleRegion(file_offset, section_end, program); | 500 return ParseSimpleRegion(file_offset, section_end, program); |
453 } | 501 } |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
551 if (!ParseRel32RelocsFromSection(section_header)) | 599 if (!ParseRel32RelocsFromSection(section_header)) |
552 return false; | 600 return false; |
553 } | 601 } |
554 if (!found_rel32) | 602 if (!found_rel32) |
555 VLOG(1) << "Warning: Found no rel32 addresses. Missing .text section?"; | 603 VLOG(1) << "Warning: Found no rel32 addresses. Missing .text section?"; |
556 | 604 |
557 return true; | 605 return true; |
558 } | 606 } |
559 | 607 |
560 } // namespace courgette | 608 } // namespace courgette |
OLD | NEW |