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 <iterator> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
| 11 #include "base/bind.h" |
11 #include "base/logging.h" | 12 #include "base/logging.h" |
12 #include "courgette/assembly_program.h" | 13 #include "courgette/assembly_program.h" |
13 #include "courgette/courgette.h" | 14 #include "courgette/courgette.h" |
14 | 15 |
15 namespace courgette { | 16 namespace courgette { |
16 | 17 |
17 namespace { | 18 namespace { |
18 | 19 |
19 // Sorts |section_headers| by file offset and stores the resulting permutation | 20 // Sorts |section_headers| by file offset and stores the resulting permutation |
20 // of section ids in |order|. | 21 // of section ids in |order|. |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 | 173 |
173 if (!ParseAbs32Relocs()) | 174 if (!ParseAbs32Relocs()) |
174 return false; | 175 return false; |
175 | 176 |
176 if (!ParseRel32RelocsFromSections()) // Does not sort rel32 locations. | 177 if (!ParseRel32RelocsFromSections()) // Does not sort rel32 locations. |
177 return false; | 178 return false; |
178 | 179 |
179 PrecomputeLabels(target); | 180 PrecomputeLabels(target); |
180 RemoveUnusedRel32Locations(target); | 181 RemoveUnusedRel32Locations(target); |
181 | 182 |
182 if (!ParseFile(target)) | 183 if (!target->GenerateInstructions( |
| 184 base::Bind(&DisassemblerElf32::ParseFile, base::Unretained(this)))) { |
183 return false; | 185 return false; |
| 186 } |
184 | 187 |
185 // Finally sort rel32 locations. | 188 // Finally sort rel32 locations. |
186 std::sort(rel32_locations_.begin(), | 189 std::sort(rel32_locations_.begin(), |
187 rel32_locations_.end(), | 190 rel32_locations_.end(), |
188 TypedRVA::IsLessThanByRVA); | 191 TypedRVA::IsLessThanByRVA); |
189 DCHECK(rel32_locations_.empty() || | 192 DCHECK(rel32_locations_.empty() || |
190 rel32_locations_.back()->rva() != kUnassignedRVA); | 193 rel32_locations_.back()->rva() != kUnassignedRVA); |
191 | 194 |
192 target->DefaultAssignIndexes(); | 195 target->DefaultAssignIndexes(); |
193 return true; | 196 return true; |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 if (string_pos >= default_string_section_size_) | 297 if (string_pos >= default_string_section_size_) |
295 return false; | 298 return false; |
296 // Safe because string section must terminate with null. | 299 // Safe because string section must terminate with null. |
297 *name = default_string_section_ + string_pos; | 300 *name = default_string_section_ + string_pos; |
298 } | 301 } |
299 return true; | 302 return true; |
300 } | 303 } |
301 | 304 |
302 CheckBool DisassemblerElf32::RVAsToFileOffsets( | 305 CheckBool DisassemblerElf32::RVAsToFileOffsets( |
303 const std::vector<RVA>& rvas, | 306 const std::vector<RVA>& rvas, |
304 std::vector<FileOffset>* file_offsets) { | 307 std::vector<FileOffset>* file_offsets) const { |
305 file_offsets->clear(); | 308 file_offsets->clear(); |
306 file_offsets->reserve(rvas.size()); | 309 file_offsets->reserve(rvas.size()); |
307 for (RVA rva : rvas) { | 310 for (RVA rva : rvas) { |
308 FileOffset file_offset = RVAToFileOffset(rva); | 311 FileOffset file_offset = RVAToFileOffset(rva); |
309 if (file_offset == kNoFileOffset) | 312 if (file_offset == kNoFileOffset) |
310 return false; | 313 return false; |
311 file_offsets->push_back(file_offset); | 314 file_offsets->push_back(file_offset); |
312 } | 315 } |
313 return true; | 316 return true; |
314 } | 317 } |
315 | 318 |
316 CheckBool DisassemblerElf32::RVAsToFileOffsets( | 319 CheckBool DisassemblerElf32::RVAsToFileOffsets( |
317 std::vector<std::unique_ptr<TypedRVA>>* typed_rvas) { | 320 std::vector<std::unique_ptr<TypedRVA>>* typed_rvas) const { |
318 for (auto& typed_rva : *typed_rvas) { | 321 for (auto& typed_rva : *typed_rvas) { |
319 FileOffset file_offset = RVAToFileOffset(typed_rva->rva()); | 322 FileOffset file_offset = RVAToFileOffset(typed_rva->rva()); |
320 if (file_offset == kNoFileOffset) | 323 if (file_offset == kNoFileOffset) |
321 return false; | 324 return false; |
322 typed_rva->set_file_offset(file_offset); | 325 typed_rva->set_file_offset(file_offset); |
323 } | 326 } |
324 return true; | 327 return true; |
325 } | 328 } |
326 | 329 |
327 RvaVisitor* DisassemblerElf32::CreateAbs32TargetRvaVisitor() { | 330 RvaVisitor* DisassemblerElf32::CreateAbs32TargetRvaVisitor() { |
(...skipping 15 matching lines...) Expand all Loading... |
343 } else { | 346 } else { |
344 // Else squeeze nullptr to end to compactify. | 347 // Else squeeze nullptr to end to compactify. |
345 if (tail_it != head_it) | 348 if (tail_it != head_it) |
346 (*tail_it).swap(*head_it); | 349 (*tail_it).swap(*head_it); |
347 ++tail_it; | 350 ++tail_it; |
348 } | 351 } |
349 } | 352 } |
350 rel32_locations_.resize(std::distance(rel32_locations_.begin(), tail_it)); | 353 rel32_locations_.resize(std::distance(rel32_locations_.begin(), tail_it)); |
351 } | 354 } |
352 | 355 |
353 CheckBool DisassemblerElf32::ParseFile(AssemblyProgram* program) { | 356 CheckBool DisassemblerElf32::ParseFile(AssemblyProgram* program, |
| 357 InstructionReceptor* receptor) const { |
354 // Walk all the bytes in the file, whether or not in a section. | 358 // Walk all the bytes in the file, whether or not in a section. |
355 FileOffset file_offset = 0; | 359 FileOffset file_offset = 0; |
356 | 360 |
357 std::vector<FileOffset> abs_offsets; | 361 std::vector<FileOffset> abs_offsets; |
358 | 362 |
359 // File parsing follows file offset order, and we visit abs32 and rel32 | 363 // File parsing follows file offset order, and we visit abs32 and rel32 |
360 // locations in lockstep. Therefore we need to extract and sort file offsets | 364 // locations in lockstep. Therefore we need to extract and sort file offsets |
361 // of all abs32 and rel32 locations. | 365 // of all abs32 and rel32 locations. |
362 if (!RVAsToFileOffsets(abs32_locations_, &abs_offsets)) | 366 if (!RVAsToFileOffsets(abs32_locations_, &abs_offsets)) |
363 return false; | 367 return false; |
(...skipping 13 matching lines...) Expand all Loading... |
377 std::vector<std::unique_ptr<TypedRVA>>::iterator end_rel = | 381 std::vector<std::unique_ptr<TypedRVA>>::iterator end_rel = |
378 rel32_locations_.end(); | 382 rel32_locations_.end(); |
379 | 383 |
380 // Visit section headers ordered by file offset. | 384 // Visit section headers ordered by file offset. |
381 for (Elf32_Half section_id : section_header_file_offset_order_) { | 385 for (Elf32_Half section_id : section_header_file_offset_order_) { |
382 const Elf32_Shdr* section_header = SectionHeader(section_id); | 386 const Elf32_Shdr* section_header = SectionHeader(section_id); |
383 | 387 |
384 if (section_header->sh_type == SHT_NOBITS) | 388 if (section_header->sh_type == SHT_NOBITS) |
385 continue; | 389 continue; |
386 | 390 |
387 if (!ParseSimpleRegion(file_offset, section_header->sh_offset, program)) | 391 if (!ParseSimpleRegion(file_offset, section_header->sh_offset, receptor)) |
388 return false; | 392 return false; |
389 | 393 |
390 file_offset = section_header->sh_offset; | 394 file_offset = section_header->sh_offset; |
391 | 395 |
392 switch (section_header->sh_type) { | 396 switch (section_header->sh_type) { |
393 case SHT_REL: | 397 case SHT_REL: |
394 if (!ParseRelocationSection(section_header, program)) | 398 if (!ParseRelocationSection(section_header, receptor)) |
395 return false; | 399 return false; |
396 file_offset = section_header->sh_offset + section_header->sh_size; | 400 file_offset = section_header->sh_offset + section_header->sh_size; |
397 break; | 401 break; |
398 case SHT_PROGBITS: | 402 case SHT_PROGBITS: |
399 if (!ParseProgbitsSection(section_header, | 403 if (!ParseProgbitsSection(section_header, ¤t_abs_offset, |
400 ¤t_abs_offset, | 404 end_abs_offset, ¤t_rel, end_rel, |
401 end_abs_offset, | 405 program, receptor)) { |
402 ¤t_rel, | |
403 end_rel, | |
404 program)) { | |
405 return false; | 406 return false; |
406 } | 407 } |
407 file_offset = section_header->sh_offset + section_header->sh_size; | 408 file_offset = section_header->sh_offset + section_header->sh_size; |
408 break; | 409 break; |
409 case SHT_INIT_ARRAY: | 410 case SHT_INIT_ARRAY: |
410 // Fall through | 411 // Fall through |
411 case SHT_FINI_ARRAY: | 412 case SHT_FINI_ARRAY: |
412 while (current_abs_offset != end_abs_offset && | 413 while (current_abs_offset != end_abs_offset && |
413 *current_abs_offset >= section_header->sh_offset && | 414 *current_abs_offset >= section_header->sh_offset && |
414 *current_abs_offset < | 415 *current_abs_offset < |
(...skipping 10 matching lines...) Expand all Loading... |
425 *current_abs_offset < | 426 *current_abs_offset < |
426 section_header->sh_offset + section_header->sh_size) { | 427 section_header->sh_offset + section_header->sh_size) { |
427 VLOG(1) << "Relocation address in unrecognized ELF section: " | 428 VLOG(1) << "Relocation address in unrecognized ELF section: " |
428 << section_header->sh_type; | 429 << section_header->sh_type; |
429 } | 430 } |
430 break; | 431 break; |
431 } | 432 } |
432 } | 433 } |
433 | 434 |
434 // Rest of the file past the last section | 435 // Rest of the file past the last section |
435 if (!ParseSimpleRegion(file_offset, length(), program)) | 436 if (!ParseSimpleRegion(file_offset, length(), receptor)) |
436 return false; | 437 return false; |
437 | 438 |
438 // Make certain we consume all of the relocations as expected | 439 // Make certain we consume all of the relocations as expected |
439 return (current_abs_offset == end_abs_offset); | 440 return (current_abs_offset == end_abs_offset); |
440 } | 441 } |
441 | 442 |
442 CheckBool DisassemblerElf32::ParseProgbitsSection( | 443 CheckBool DisassemblerElf32::ParseProgbitsSection( |
443 const Elf32_Shdr* section_header, | 444 const Elf32_Shdr* section_header, |
444 std::vector<FileOffset>::iterator* current_abs_offset, | 445 std::vector<FileOffset>::iterator* current_abs_offset, |
445 std::vector<FileOffset>::iterator end_abs_offset, | 446 std::vector<FileOffset>::iterator end_abs_offset, |
446 std::vector<std::unique_ptr<TypedRVA>>::iterator* current_rel, | 447 std::vector<std::unique_ptr<TypedRVA>>::iterator* current_rel, |
447 std::vector<std::unique_ptr<TypedRVA>>::iterator end_rel, | 448 std::vector<std::unique_ptr<TypedRVA>>::iterator end_rel, |
448 AssemblyProgram* program) { | 449 AssemblyProgram* program, |
| 450 InstructionReceptor* receptor) const { |
449 // Walk all the bytes in the file, whether or not in a section. | 451 // Walk all the bytes in the file, whether or not in a section. |
450 FileOffset file_offset = section_header->sh_offset; | 452 FileOffset file_offset = section_header->sh_offset; |
451 FileOffset section_end = section_header->sh_offset + section_header->sh_size; | 453 FileOffset section_end = section_header->sh_offset + section_header->sh_size; |
452 | 454 |
453 Elf32_Addr origin = section_header->sh_addr; | 455 Elf32_Addr origin = section_header->sh_addr; |
454 FileOffset origin_offset = section_header->sh_offset; | 456 FileOffset origin_offset = section_header->sh_offset; |
455 if (!program->EmitOriginInstruction(origin)) | 457 if (!receptor->EmitOrigin(origin)) |
456 return false; | 458 return false; |
457 | 459 |
458 while (file_offset < section_end) { | 460 while (file_offset < section_end) { |
459 if (*current_abs_offset != end_abs_offset && | 461 if (*current_abs_offset != end_abs_offset && |
460 file_offset > **current_abs_offset) | 462 file_offset > **current_abs_offset) |
461 return false; | 463 return false; |
462 | 464 |
463 while (*current_rel != end_rel && | 465 while (*current_rel != end_rel && |
464 file_offset > (**current_rel)->file_offset()) { | 466 file_offset > (**current_rel)->file_offset()) { |
465 ++(*current_rel); | 467 ++(*current_rel); |
466 } | 468 } |
467 | 469 |
468 FileOffset next_relocation = section_end; | 470 FileOffset next_relocation = section_end; |
469 | 471 |
470 if (*current_abs_offset != end_abs_offset && | 472 if (*current_abs_offset != end_abs_offset && |
471 next_relocation > **current_abs_offset) | 473 next_relocation > **current_abs_offset) |
472 next_relocation = **current_abs_offset; | 474 next_relocation = **current_abs_offset; |
473 | 475 |
474 // Rel offsets are heuristically derived, and might (incorrectly) overlap | 476 // Rel offsets are heuristically derived, and might (incorrectly) overlap |
475 // an Abs value, or the end of the section, so +3 to make sure there is | 477 // an Abs value, or the end of the section, so +3 to make sure there is |
476 // room for the full 4 byte value. | 478 // room for the full 4 byte value. |
477 if (*current_rel != end_rel && | 479 if (*current_rel != end_rel && |
478 next_relocation > ((**current_rel)->file_offset() + 3)) | 480 next_relocation > ((**current_rel)->file_offset() + 3)) |
479 next_relocation = (**current_rel)->file_offset(); | 481 next_relocation = (**current_rel)->file_offset(); |
480 | 482 |
481 if (next_relocation > file_offset) { | 483 if (next_relocation > file_offset) { |
482 if (!ParseSimpleRegion(file_offset, next_relocation, program)) | 484 if (!ParseSimpleRegion(file_offset, next_relocation, receptor)) |
483 return false; | 485 return false; |
484 | 486 |
485 file_offset = next_relocation; | 487 file_offset = next_relocation; |
486 continue; | 488 continue; |
487 } | 489 } |
488 | 490 |
489 if (*current_abs_offset != end_abs_offset && | 491 if (*current_abs_offset != end_abs_offset && |
490 file_offset == **current_abs_offset) { | 492 file_offset == **current_abs_offset) { |
491 RVA target_rva = PointerToTargetRVA(FileOffsetToPointer(file_offset)); | 493 RVA target_rva = PointerToTargetRVA(FileOffsetToPointer(file_offset)); |
492 DCHECK_NE(kNoRVA, target_rva); | 494 DCHECK_NE(kNoRVA, target_rva); |
493 | 495 |
494 Label* label = program->FindAbs32Label(target_rva); | 496 Label* label = program->FindAbs32Label(target_rva); |
495 CHECK(label); | 497 CHECK(label); |
496 if (!program->EmitAbs32(label)) | 498 if (!receptor->EmitAbs32(label)) |
497 return false; | 499 return false; |
498 file_offset += sizeof(RVA); | 500 file_offset += sizeof(RVA); |
499 ++(*current_abs_offset); | 501 ++(*current_abs_offset); |
500 continue; | 502 continue; |
501 } | 503 } |
502 | 504 |
503 if (*current_rel != end_rel && | 505 if (*current_rel != end_rel && |
504 file_offset == (**current_rel)->file_offset()) { | 506 file_offset == (**current_rel)->file_offset()) { |
505 uint32_t relative_target = (**current_rel)->relative_target(); | 507 uint32_t relative_target = (**current_rel)->relative_target(); |
506 CHECK_EQ(RVA(origin + (file_offset - origin_offset)), | 508 CHECK_EQ(RVA(origin + (file_offset - origin_offset)), |
507 (**current_rel)->rva()); | 509 (**current_rel)->rva()); |
508 // This cast is for 64 bit systems, and is only safe because we | 510 // This cast is for 64 bit systems, and is only safe because we |
509 // are working on 32 bit executables. | 511 // are working on 32 bit executables. |
510 RVA target_rva = (RVA)(origin + (file_offset - origin_offset) + | 512 RVA target_rva = (RVA)(origin + (file_offset - origin_offset) + |
511 relative_target); | 513 relative_target); |
512 | 514 |
513 Label* label = program->FindRel32Label(target_rva); | 515 Label* label = program->FindRel32Label(target_rva); |
514 CHECK(label); | 516 CHECK(label); |
515 | 517 |
516 if (!(**current_rel)->EmitInstruction(program, label)) | 518 if (!(**current_rel)->EmitInstruction(label, receptor)) |
517 return false; | 519 return false; |
518 file_offset += (**current_rel)->op_size(); | 520 file_offset += (**current_rel)->op_size(); |
519 ++(*current_rel); | 521 ++(*current_rel); |
520 continue; | 522 continue; |
521 } | 523 } |
522 } | 524 } |
523 | 525 |
524 // Rest of the section (if any) | 526 // Rest of the section (if any) |
525 return ParseSimpleRegion(file_offset, section_end, program); | 527 return ParseSimpleRegion(file_offset, section_end, receptor); |
526 } | 528 } |
527 | 529 |
528 CheckBool DisassemblerElf32::ParseSimpleRegion(FileOffset start_file_offset, | 530 CheckBool DisassemblerElf32::ParseSimpleRegion( |
529 FileOffset end_file_offset, | 531 FileOffset start_file_offset, |
530 AssemblyProgram* program) { | 532 FileOffset end_file_offset, |
| 533 InstructionReceptor* receptor) const { |
531 // Callers don't guarantee start < end | 534 // Callers don't guarantee start < end |
532 if (start_file_offset >= end_file_offset) | 535 if (start_file_offset >= end_file_offset) |
533 return true; | 536 return true; |
534 | 537 |
535 const size_t len = end_file_offset - start_file_offset; | 538 const size_t len = end_file_offset - start_file_offset; |
536 | 539 |
537 if (!program->EmitBytesInstruction(FileOffsetToPointer(start_file_offset), | 540 if (!receptor->EmitMultipleBytes(FileOffsetToPointer(start_file_offset), |
538 len)) { | 541 len)) { |
539 return false; | 542 return false; |
540 } | 543 } |
541 | 544 |
542 return true; | 545 return true; |
543 } | 546 } |
544 | 547 |
545 CheckBool DisassemblerElf32::ParseAbs32Relocs() { | 548 CheckBool DisassemblerElf32::ParseAbs32Relocs() { |
546 abs32_locations_.clear(); | 549 abs32_locations_.clear(); |
547 | 550 |
548 // Loop through sections for relocation sections | 551 // Loop through sections for relocation sections |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
624 if (!ParseRel32RelocsFromSection(section_header)) | 627 if (!ParseRel32RelocsFromSection(section_header)) |
625 return false; | 628 return false; |
626 } | 629 } |
627 if (!found_rel32) | 630 if (!found_rel32) |
628 VLOG(1) << "Warning: Found no rel32 addresses. Missing .text section?"; | 631 VLOG(1) << "Warning: Found no rel32 addresses. Missing .text section?"; |
629 | 632 |
630 return true; | 633 return true; |
631 } | 634 } |
632 | 635 |
633 } // namespace courgette | 636 } // namespace courgette |
OLD | NEW |