| 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 |