|
2 | 2 | #include "elf_file.h" |
3 | 3 | #include "elf_file_i.h" |
4 | 4 | #include "elf_api_interface.h" |
| 5 | +#include "../api_hashtable/api_hashtable.h" |
5 | 6 |
|
6 | 7 | #define TAG "elf" |
7 | 8 |
|
8 | 9 | #define ELF_NAME_BUFFER_LEN 32 |
9 | 10 | #define SECTION_OFFSET(e, n) ((e)->section_table + (n) * sizeof(Elf32_Shdr)) |
10 | 11 | #define IS_FLAGS_SET(v, m) (((v) & (m)) == (m)) |
11 | 12 | #define RESOLVER_THREAD_YIELD_STEP 30 |
| 13 | +#define FAST_RELOCATION_VERSION 1 |
12 | 14 |
|
13 | 15 | // #define ELF_DEBUG_LOG 1 |
14 | 16 |
|
@@ -71,6 +73,7 @@ static ELFSection* elf_file_get_or_put_section(ELFFile* elf, const char* name) { |
71 | 73 | .size = 0, |
72 | 74 | .rel_count = 0, |
73 | 75 | .rel_offset = 0, |
| 76 | + .fast_rel = NULL, |
74 | 77 | }); |
75 | 78 | section_p = elf_file_get_section(elf, name); |
76 | 79 | } |
@@ -168,7 +171,8 @@ static ELFSection* elf_section_of(ELFFile* elf, int index) { |
168 | 171 | static Elf32_Addr elf_address_of(ELFFile* elf, Elf32_Sym* sym, const char* sName) { |
169 | 172 | if(sym->st_shndx == SHN_UNDEF) { |
170 | 173 | Elf32_Addr addr = 0; |
171 | | - if(elf->api_interface->resolver_callback(elf->api_interface, sName, &addr)) { |
| 174 | + uint32_t hash = elf_symbolname_hash(sName); |
| 175 | + if(elf->api_interface->resolver_callback(elf->api_interface, hash, &addr)) { |
172 | 176 | return addr; |
173 | 177 | } |
174 | 178 | } else { |
@@ -424,6 +428,7 @@ typedef enum { |
424 | 428 | SectionTypeSymTab = 1 << 3, |
425 | 429 | SectionTypeStrTab = 1 << 4, |
426 | 430 | SectionTypeDebugLink = 1 << 5, |
| 431 | + SectionTypeFastRelData = 1 << 6, |
427 | 432 |
|
428 | 433 | SectionTypeValid = SectionTypeSymTab | SectionTypeStrTab, |
429 | 434 | } SectionType; |
@@ -505,7 +510,8 @@ static SectionType elf_preload_section( |
505 | 510 | // TODO: how to do it not by name? |
506 | 511 | // .ARM: type 0x70000001, flags SHF_ALLOC | SHF_LINK_ORDER |
507 | 512 | // .rel.ARM: type 0x9, flags SHT_REL |
508 | | - if(str_prefix(name, ".ARM.") || str_prefix(name, ".rel.ARM.")) { |
| 513 | + if(str_prefix(name, ".ARM.") || str_prefix(name, ".rel.ARM.") || |
| 514 | + str_prefix(name, ".fast.rel.ARM.")) { |
509 | 515 | FURI_LOG_D(TAG, "Ignoring ARM section"); |
510 | 516 | return SectionTypeUnused; |
511 | 517 | } |
@@ -536,11 +542,31 @@ static SectionType elf_preload_section( |
536 | 542 |
|
537 | 543 | // Load link info section |
538 | 544 | if(section_header->sh_flags & SHF_INFO_LINK) { |
539 | | - name = name + strlen(".rel"); |
| 545 | + if(str_prefix(name, ".rel")) { |
| 546 | + name = name + strlen(".rel"); |
| 547 | + ELFSection* section_p = elf_file_get_or_put_section(elf, name); |
| 548 | + section_p->rel_count = section_header->sh_size / sizeof(Elf32_Rel); |
| 549 | + section_p->rel_offset = section_header->sh_offset; |
| 550 | + return SectionTypeRelData; |
| 551 | + } else { |
| 552 | + FURI_LOG_E(TAG, "Unknown link info section '%s'", name); |
| 553 | + return SectionTypeERROR; |
| 554 | + } |
| 555 | + } |
| 556 | + |
| 557 | + // Load fast rel section |
| 558 | + if(str_prefix(name, ".fast.rel")) { |
| 559 | + name = name + strlen(".fast.rel"); |
540 | 560 | ELFSection* section_p = elf_file_get_or_put_section(elf, name); |
541 | | - section_p->rel_count = section_header->sh_size / sizeof(Elf32_Rel); |
542 | | - section_p->rel_offset = section_header->sh_offset; |
543 | | - return SectionTypeRelData; |
| 561 | + section_p->fast_rel = malloc(sizeof(ELFSection)); |
| 562 | + |
| 563 | + if(!elf_load_section_data(elf, section_p->fast_rel, section_header)) { |
| 564 | + FURI_LOG_E(TAG, "Error loading section '%s'", name); |
| 565 | + return SectionTypeERROR; |
| 566 | + } |
| 567 | + |
| 568 | + FURI_LOG_D(TAG, "Loaded fast rel section for '%s'", name); |
| 569 | + return SectionTypeFastRelData; |
544 | 570 | } |
545 | 571 |
|
546 | 572 | // Load symbol table |
@@ -571,8 +597,90 @@ static SectionType elf_preload_section( |
571 | 597 | return SectionTypeUnused; |
572 | 598 | } |
573 | 599 |
|
| 600 | +static Elf32_Addr elf_address_of_by_hash(ELFFile* elf, uint32_t hash) { |
| 601 | + Elf32_Addr addr = 0; |
| 602 | + if(elf->api_interface->resolver_callback(elf->api_interface, hash, &addr)) { |
| 603 | + return addr; |
| 604 | + } |
| 605 | + return ELF_INVALID_ADDRESS; |
| 606 | +} |
| 607 | + |
| 608 | +static bool elf_relocate_fast(ELFFile* elf, ELFSection* s) { |
| 609 | + UNUSED(elf); |
| 610 | + const uint8_t* start = s->fast_rel->data; |
| 611 | + const uint8_t version = *start; |
| 612 | + |
| 613 | + if(version != FAST_RELOCATION_VERSION) { |
| 614 | + FURI_LOG_E(TAG, "Unsupported fast relocation version %d", version); |
| 615 | + return false; |
| 616 | + } |
| 617 | + start += 1; |
| 618 | + |
| 619 | + const uint32_t records_count = *((uint32_t*)start); |
| 620 | + start += 4; |
| 621 | + FURI_LOG_D(TAG, "Fast relocation records count: %ld", records_count); |
| 622 | + |
| 623 | + for(uint32_t i = 0; i < records_count; i++) { |
| 624 | + bool is_section = (*start & (0x1 << 7)) ? true : false; |
| 625 | + uint8_t type = *start & 0x7F; |
| 626 | + start += 1; |
| 627 | + uint32_t hash_or_section_index = *((uint32_t*)start); |
| 628 | + start += 4; |
| 629 | + |
| 630 | + uint32_t section_value = ELF_INVALID_ADDRESS; |
| 631 | + if(is_section) { |
| 632 | + section_value = *((uint32_t*)start); |
| 633 | + start += 4; |
| 634 | + } |
| 635 | + |
| 636 | + const uint32_t offsets_count = *((uint32_t*)start); |
| 637 | + start += 4; |
| 638 | + |
| 639 | + FURI_LOG_D( |
| 640 | + TAG, |
| 641 | + "Fast relocation record %ld: is_section=%d, type=%d, hash_or_section_index=%lX, offsets_count=%ld", |
| 642 | + i, |
| 643 | + is_section, |
| 644 | + type, |
| 645 | + hash_or_section_index, |
| 646 | + offsets_count); |
| 647 | + |
| 648 | + Elf32_Addr address = 0; |
| 649 | + if(is_section) { |
| 650 | + ELFSection* symSec = elf_section_of(elf, hash_or_section_index); |
| 651 | + if(symSec) { |
| 652 | + address = ((Elf32_Addr)symSec->data) + section_value; |
| 653 | + } |
| 654 | + } else { |
| 655 | + address = elf_address_of_by_hash(elf, hash_or_section_index); |
| 656 | + } |
| 657 | + |
| 658 | + if(address == ELF_INVALID_ADDRESS) { |
| 659 | + FURI_LOG_E(TAG, "Failed to resolve address for hash %lX", hash_or_section_index); |
| 660 | + return false; |
| 661 | + } |
| 662 | + |
| 663 | + for(uint32_t j = 0; j < offsets_count; j++) { |
| 664 | + uint32_t offset = *((uint32_t*)start) & 0x00FFFFFF; |
| 665 | + start += 3; |
| 666 | + // FURI_LOG_I(TAG, " Fast relocation offset %ld: %ld", j, offset); |
| 667 | + Elf32_Addr relAddr = ((Elf32_Addr)s->data) + offset; |
| 668 | + elf_relocate_symbol(elf, relAddr, type, address); |
| 669 | + } |
| 670 | + } |
| 671 | + |
| 672 | + aligned_free(s->fast_rel->data); |
| 673 | + free(s->fast_rel); |
| 674 | + s->fast_rel = NULL; |
| 675 | + |
| 676 | + return true; |
| 677 | +} |
| 678 | + |
574 | 679 | static bool elf_relocate_section(ELFFile* elf, ELFSection* section) { |
575 | | - if(section->rel_count) { |
| 680 | + if(section->fast_rel) { |
| 681 | + FURI_LOG_D(TAG, "Fast relocating section"); |
| 682 | + return elf_relocate_fast(elf, section); |
| 683 | + } else if(section->rel_count) { |
576 | 684 | FURI_LOG_D(TAG, "Relocating section"); |
577 | 685 | return elf_relocate(elf, section); |
578 | 686 | } else { |
@@ -630,6 +738,10 @@ void elf_file_free(ELFFile* elf) { |
630 | 738 | if(itref->value.data) { |
631 | 739 | aligned_free(itref->value.data); |
632 | 740 | } |
| 741 | + if(itref->value.fast_rel) { |
| 742 | + aligned_free(itref->value.fast_rel->data); |
| 743 | + free(itref->value.fast_rel); |
| 744 | + } |
633 | 745 | free((void*)itref->key); |
634 | 746 | } |
635 | 747 |
|
|
0 commit comments