handle_elf may perform multiple iterations over section headers to ensure that if a section is included in the debug file, then its sh_link and sh_info sections are also included in the debug file.
handle_elf contains an optimization where an additional iteration may be avoided if the sh_link or sh_info of a section marked for inclusion in the main elf file have yet to be investigated by the current iteration. The additional iteration is scheduled only if the loop index 'cnt' has already passed the sh_link or sh_info. This optimization can cause a bug where the sh_link or sh_info of a section in the debug file may not be present in the debug file. sh_link/sh_info cross references between .symtab and .rel.* sections might be ordered such that .symtab is marked for stripping while iterating over all the .rel.debug_* sections that reference .symtab in their sh_link, resulting in no additional debug-preservation handling for .symtab. However, it's possible later in the loop for a .rel.* section to refer to an allocated section via sh_info and .symtab via sh_link. In this case, .symtab gets marked for preservation in the main elf file. If no other .rel.debug_* sections are encountered for the rest of the iteration, then debug-preservation isn't triggered for .symtab. This results in the debug file containing a NOBITS .symtab despite .rel.debug_* sections referencing .symtab in their sh_link. If --reloc-debug-sections is given, a segfault or error may occur when attempting to resolve these relocations. Fix this by unconditionally scheduling another iteration across section headers when an sh_link or sh_info gets flagged for inclusion in the main elf file. For the above case, the additional iteration will trigger debug-preservation for .symtab upon detection that a .rel.debug_* sh_link is being kept in the main elf file. .symtab will then be present in both the main elf file and debug file. https://sourceware.org/bugzilla/show_bug.cgi?id=34097 --- src/strip.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/strip.c b/src/strip.c index 20cc8a22..a8ecc80d 100644 --- a/src/strip.c +++ b/src/strip.c @@ -1575,7 +1575,10 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (shdr_info[shdr_info[cnt].shdr.sh_link].idx == 0) { shdr_info[shdr_info[cnt].shdr.sh_link].idx = 1; - changes |= shdr_info[cnt].shdr.sh_link < cnt; + /* Force another iteration in case we need to propagate this + change to a previous section (either the sh_link section + itself or another section that references it). */ + changes = true; } /* Handle references through sh_info. */ @@ -1586,7 +1589,11 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, else if ( shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0) { shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1; - changes |= shdr_info[cnt].shdr.sh_info < cnt; + /* Force another iteration in case we need to propagate + this change to a previous section (either the sh_info + section itself or another section that references + it). */ + changes = true; } } -- 2.54.0
