+
+ if (iheaders == NULL || oheaders == NULL)
+ return TRUE;
+
+ /* Possibly copy the sh_info and sh_link fields. */
+ for (i = 1; i < elf_numsections (obfd); i++)
+ {
+ unsigned int j;
+ Elf_Internal_Shdr * oheader = oheaders[i];
+
+ if (oheader == NULL
+ || (oheader->sh_type != SHT_NOBITS
+ && oheader->sh_type < SHT_LOOS)
+ || oheader->sh_size == 0
+ || (oheader->sh_info != 0 && oheader->sh_link != 0))
+ continue;
+
+ /* Scan for the matching section in the input bfd.
+ FIXME: We could use something better than a linear scan here.
+ Unfortunately we cannot compare names as the output string table
+ is empty, so instead we check size, address and type. */
+ for (j = 1; j < elf_numsections (ibfd); j++)
+ {
+ Elf_Internal_Shdr * iheader = iheaders[j];
+
+ /* Since --only-keep-debug turns all non-debug sections into
+ SHT_NOBITS sections, the output SHT_NOBITS type matches any
+ input type. */
+ if ((oheader->sh_type == SHT_NOBITS
+ || iheader->sh_type == oheader->sh_type)
+ && iheader->sh_flags == oheader->sh_flags
+ && iheader->sh_addralign == oheader->sh_addralign
+ && iheader->sh_entsize == oheader->sh_entsize
+ && iheader->sh_size == oheader->sh_size
+ && iheader->sh_addr == oheader->sh_addr
+ && (iheader->sh_info != oheader->sh_info
+ || iheader->sh_link != oheader->sh_link))
+ {
+ /* PR 19938: Attempt to preserve the sh_link and sh_info fields
+ of OS and Processor specific sections. We try harder for
+ these sections, because this is not just about matching
+ stripped binaries to their originals. */
+ if (oheader->sh_type >= SHT_LOOS)
+ {
+ const struct elf_backend_data *bed = get_elf_backend_data (obfd);
+ bfd_boolean changed = FALSE;
+ unsigned int sh_link;
+
+ /* Allow the target a chance to decide how these fields should
+ be set. */
+ if (bed->elf_backend_set_special_section_info_and_link != NULL
+ && bed->elf_backend_set_special_section_info_and_link
+ (ibfd, obfd, iheader, oheader))
+ break;
+
+ /* We have iheader which matches oheader, but which has
+ non-zero sh_info and/or sh_link fields. Attempt to
+ follow those links and find the section in the output
+ bfd which corresponds to the linked section in the input
+ bfd. */
+ if (iheader->sh_link != SHN_UNDEF)
+ {
+ sh_link = find_link (obfd,
+ iheaders[iheader->sh_link],
+ iheader->sh_link);
+ if (sh_link != SHN_UNDEF)
+ {
+ oheader->sh_link = sh_link;
+ changed = TRUE;
+ }
+ else
+ /* FIXME: Should we install iheader->sh_link
+ if we could not find a match ? */
+ (* _bfd_error_handler)
+ (_("%B: Failed to find link section for section %d"),
+ obfd, i);
+ }
+
+ if (iheader->sh_info)
+ {
+ /* The sh_info field can hold arbitrary information,
+ but if the SHF_LINK_INFO flag is set then it
+ should be interpreted as a section index. */
+ if (iheader->sh_flags & SHF_INFO_LINK)
+ sh_link = find_link (obfd,
+ iheaders[iheader->sh_info],
+ iheader->sh_info);
+ else
+ /* No idea what it means - just copy it. */
+ sh_link = iheader->sh_info;
+
+ if (sh_link != SHN_UNDEF)
+ {
+ oheader->sh_info = sh_link;
+ changed = TRUE;
+ }
+ else
+ (* _bfd_error_handler)
+ (_("%B: Failed to find info section for section %d"),
+ obfd, i);
+ }
+
+ if (changed)
+ break;
+ }
+ else
+ {
+ /* This is an feature for objcopy --only-keep-debug:
+ When a section's type is changed to NOBITS, we preserve
+ the sh_link and sh_info fields so that they can be
+ matched up with the original.
+
+ Note: Strictly speaking these assignments are wrong.
+ The sh_link and sh_info fields should point to the
+ relevent sections in the output BFD, which may not be in
+ the same location as they were in the input BFD. But
+ the whole point of this action is to preserve the
+ original values of the sh_link and sh_info fields, so
+ that they can be matched up with the section headers in
+ the original file. So strictly speaking we may be
+ creating an invalid ELF file, but it is only for a file
+ that just contains debug info and only for sections
+ without any contents. */
+ if (oheader->sh_link == 0)
+ oheader->sh_link = iheader->sh_link;
+ if (oheader->sh_info == 0)
+ oheader->sh_info = iheader->sh_info;
+ break;
+ }
+ }
+ }
+ }
+