diff options
Diffstat (limited to 'src/unstrip.c')
-rw-r--r-- | src/unstrip.c | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/src/unstrip.c b/src/unstrip.c index 0c01baad..55f68cb5 100644 --- a/src/unstrip.c +++ b/src/unstrip.c @@ -598,21 +598,31 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, /* Adjust all the relocation sections in the file. */ static void adjust_all_relocs (Elf *elf, Elf_Scn *symtab, const GElf_Shdr *symshdr, - size_t map[], size_t map_size) + size_t map[], size_t map_size, bool *scn_filter) { size_t new_sh_link = elf_ndxscn (symtab); Elf_Scn *scn = NULL; while ((scn = elf_nextscn (elf, scn)) != NULL) if (scn != symtab) { + if (scn_filter != NULL) + { + size_t ndx = elf_ndxscn (scn); + + /* Don't redo sections that were already done by adjust_relocs + for the stripped symtab. This is to avoid mapping a + relocation's symbol index from X to Y during the first + adjust_relocs and then wrongly mapping it from Y to Z during + a second call. */ + if (scn_filter[ndx]) + continue; + } + GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); ELF_CHECK (shdr != NULL, _("cannot get section header: %s")); - /* Don't redo SHT_GROUP, groups are in both the stripped and debug, - it will already have been done by adjust_relocs for the - stripped_symtab. */ - if (shdr->sh_type != SHT_NOBITS && shdr->sh_type != SHT_GROUP - && shdr->sh_link == new_sh_link) + + if (shdr->sh_type != SHT_NOBITS && shdr->sh_link == new_sh_link) adjust_relocs (scn, scn, shdr, map, map_size, symshdr); } } @@ -697,7 +707,7 @@ add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum, } /* Adjust any relocations referring to the old symbol table. */ - adjust_all_relocs (elf, symscn, shdr, symndx_map, nsym - 1); + adjust_all_relocs (elf, symscn, shdr, symndx_map, nsym - 1, NULL); return symdata; } @@ -874,6 +884,7 @@ collect_symbols (Elf *outelf, bool rel, Elf_Scn *symscn, Elf_Scn *strscn, s->shndx = shndx; s->info.info = sym->st_info; s->info.other = sym->st_other; + s->duplicate = NULL; if (scnmap != NULL && shndx != SHN_UNDEF && shndx < SHN_LORESERVE) s->shndx = scnmap[shndx - 1]; @@ -903,12 +914,7 @@ collect_symbols (Elf *outelf, bool rel, Elf_Scn *symscn, Elf_Scn *strscn, if (s1->value > s2->value) \ return 1 -/* Symbol comparison used to sort symbols in preparation for deduplication. - - This function must ensure a consistent ordering of duplicates even when - used with an unstable sort function such as qsort. If duplicate symbols - aren't sorted in a consistent order, the symbol index map can become - corrupt. */ +/* Symbol comparison used to sort symbols in preparation for deduplication. */ static int compare_symbols (const void *a, const void *b) { @@ -931,7 +937,7 @@ compare_symbols (const void *a, const void *b) Compare map positions to ensure that duplicate symbols are ordered consistently even if the sort function is unstable. */ CMP (map); - error_exit (0, "found two identical index map positions."); + error_exit (0, _("found two identical index map positions.")); } /* Symbol comparison used to deduplicate symbols found in both the stripped @@ -939,7 +945,7 @@ compare_symbols (const void *a, const void *b) Similar to compare_symbols, but does not differentiate symbols based on their position in the symbol index map. Duplicates can't be found - by comparing index map postions because duplicates still have distinct + by comparing index map postions because they always have distinct positions in the map. */ static int compare_symbols_duplicate (const void *a, const void *b) @@ -982,13 +988,13 @@ compare_symbols_output (const void *a, const void *b) /* binutils always puts section symbols in section index order. */ CMP (shndx); else if (s1 != s2) - error_exit (0, "section symbols in unexpected order"); + error_exit (0, _("section symbols in unexpected order")); } /* Nothing really matters, so preserve the original order. */ CMP (map); else if (s1 != s2) - error_exit (0, "found two identical symbols"); + error_exit (0, _("found two identical symbols")); } return cmp; @@ -2029,6 +2035,9 @@ more sections in stripped file than debug file -- arguments reversed?")); elf_flagdata (symdata, ELF_C_SET, ELF_F_DIRTY); update_shdr (unstripped_symtab, shdr); + bool scn_adjusted[unstripped_shnum]; + memset (scn_adjusted, 0, sizeof scn_adjusted); + if (stripped_symtab != NULL) { /* Adjust any relocations referring to the old symbol table. */ @@ -2037,14 +2046,18 @@ more sections in stripped file than debug file -- arguments reversed?")); sec < §ions[stripped_shnum - 1]; ++sec) if (sec->outscn != NULL && sec->shdr.sh_link == old_sh_link) - adjust_relocs (sec->outscn, sec->scn, &sec->shdr, - symndx_map, total_syms, shdr); + { + adjust_relocs (sec->outscn, sec->scn, &sec->shdr, + symndx_map, total_syms, shdr); + scn_adjusted[elf_ndxscn (sec->outscn)] = true; + } } /* Also adjust references to the other old symbol table. */ adjust_all_relocs (unstripped, unstripped_symtab, shdr, &symndx_map[stripped_nsym - 1], - total_syms - (stripped_nsym - 1)); + total_syms - (stripped_nsym - 1), + scn_adjusted); free (symbols); free (symndx_map); |