/* Find an index section that is linked to this symtab section. */
for (entry = elf_symtab_shndx_list (ibfd); entry != NULL; entry = entry->next)
- if (sections[entry->hdr.sh_link] == symtab_hdr)
- {
- shndx_hdr = & entry->hdr;
- break;
- };
+ {
+ /* PR 20063. */
+ if (entry->hdr.sh_link >= elf_numsections (ibfd))
+ continue;
+
+ if (sections[entry->hdr.sh_link] == symtab_hdr)
+ {
+ shndx_hdr = & entry->hdr;
+ break;
+ };
+ }
if (shndx_hdr == NULL)
{
{
flags |= SEC_MERGE;
newsect->entsize = hdr->sh_entsize;
- if ((hdr->sh_flags & SHF_STRINGS) != 0)
- flags |= SEC_STRINGS;
}
+ if ((hdr->sh_flags & SHF_STRINGS) != 0)
+ flags |= SEC_STRINGS;
if (hdr->sh_flags & SHF_GROUP)
if (!setup_group (abfd, hdr, newsect))
return FALSE;
return TRUE;
}
-const char *const bfd_elf_section_type_names[] = {
+const char *const bfd_elf_section_type_names[] =
+{
"SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB",
"SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE",
"SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM",
return bfd_reloc_continue;
}
\f
+/* Returns TRUE if section A matches section B.
+ Names, addresses and links may be different, but everything else
+ should be the same. */
+
+static bfd_boolean
+section_match (const Elf_Internal_Shdr * a,
+ const Elf_Internal_Shdr * b)
+{
+ return
+ a->sh_type == b->sh_type
+ && (a->sh_flags & ~ SHF_INFO_LINK)
+ == (b->sh_flags & ~ SHF_INFO_LINK)
+ && a->sh_addralign == b->sh_addralign
+ && a->sh_size == b->sh_size
+ && a->sh_entsize == b->sh_entsize
+ /* FIXME: Check sh_addr ? */
+ ;
+}
+
+/* Find a section in OBFD that has the same characteristics
+ as IHEADER. Return the index of this section or SHN_UNDEF if
+ none can be found. Check's section HINT first, as this is likely
+ to be the correct section. */
+
+static unsigned int
+find_link (const bfd * obfd, const Elf_Internal_Shdr * iheader, const unsigned int hint)
+{
+ Elf_Internal_Shdr ** oheaders = elf_elfsections (obfd);
+ unsigned int i;
+
+ if (section_match (oheaders[hint], iheader))
+ return hint;
+
+ for (i = 1; i < elf_numsections (obfd); i++)
+ {
+ Elf_Internal_Shdr * oheader = oheaders[i];
+
+ if (section_match (oheader, iheader))
+ /* FIXME: Do we care if there is a potential for
+ multiple matches ? */
+ return i;
+ }
+
+ return SHN_UNDEF;
+}
+
+/* PR 19938: Attempt to set the ELF section header fields of an OS or
+ Processor specific section, based upon a matching input section.
+ Returns TRUE upon success, FALSE otherwise. */
+
+static bfd_boolean
+copy_special_section_fields (const bfd *ibfd,
+ bfd *obfd,
+ const Elf_Internal_Shdr *iheader,
+ Elf_Internal_Shdr *oheader,
+ const unsigned int secnum)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (obfd);
+ const Elf_Internal_Shdr **iheaders = (const Elf_Internal_Shdr **) elf_elfsections (ibfd);
+ bfd_boolean changed = FALSE;
+ unsigned int sh_link;
+
+ if (oheader->sh_type == SHT_NOBITS)
+ {
+ /* This is a 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;
+ return TRUE;
+ }
+
+ /* Allow the target a chance to decide how these fields should be set. */
+ if (bed->elf_backend_copy_special_section_fields != NULL
+ && bed->elf_backend_copy_special_section_fields
+ (ibfd, obfd, iheader, oheader))
+ return TRUE;
+
+ /* We have an iheader which might match oheader, and 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, secnum);
+ }
+
+ 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);
+ if (sh_link != SHN_UNDEF)
+ oheader->sh_flags |= SHF_INFO_LINK;
+ }
+ 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, secnum);
+ }
+
+ return changed;
+}
+
/* Copy the program header and other data from one object module to
another. */
bfd_boolean
_bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
{
+ const Elf_Internal_Shdr **iheaders = (const Elf_Internal_Shdr **) elf_elfsections (ibfd);
+ Elf_Internal_Shdr **oheaders = elf_elfsections (obfd);
+ const struct elf_backend_data *bed;
+ unsigned int i;
+
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
- || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return TRUE;
if (!elf_flags_init (obfd))
elf_elfheader (obfd)->e_ident[EI_OSABI] =
elf_elfheader (ibfd)->e_ident[EI_OSABI];
+ /* If set, copy the EI_ABIVERSION field. */
+ if (elf_elfheader (ibfd)->e_ident[EI_ABIVERSION])
+ elf_elfheader (obfd)->e_ident[EI_ABIVERSION]
+ = elf_elfheader (ibfd)->e_ident[EI_ABIVERSION];
+
/* Copy object attributes. */
_bfd_elf_copy_obj_attributes (ibfd, obfd);
- /* 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. */
- Elf_Internal_Shdr ** iheaders = elf_elfsections (ibfd);
- Elf_Internal_Shdr ** oheaders = elf_elfsections (obfd);
+ if (iheaders == NULL || oheaders == NULL)
+ return TRUE;
+
+ bed = get_elf_backend_data (obfd);
- if (iheaders != NULL && oheaders != NULL)
+ /* Possibly copy other fields in the section header. */
+ for (i = 1; i < elf_numsections (obfd); i++)
{
- unsigned int i;
+ unsigned int j;
+ Elf_Internal_Shdr * oheader = oheaders[i];
+
+ /* Ignore ordinary sections. SHT_NOBITS sections are considered however
+ because of a special case need for generating separate debug info
+ files. See below for more details. */
+ if (oheader == NULL
+ || (oheader->sh_type != SHT_NOBITS
+ && oheader->sh_type < SHT_LOOS))
+ continue;
- for (i = 0; i < elf_numsections (obfd); i++)
+ /* Ignore empty sections, and sections whose
+ fields have already been initialised. */
+ if (oheader->sh_size == 0
+ || (oheader->sh_info != 0 && oheader->sh_link != 0))
+ continue;
+
+ /* Scan for the matching section in the input bfd.
+ First we try for a direct mapping between the input and output sections. */
+ for (j = 1; j < elf_numsections (ibfd); j++)
{
- unsigned int j;
- Elf_Internal_Shdr * oheader = oheaders[i];
+ const Elf_Internal_Shdr * iheader = iheaders[j];
- if (oheader == NULL
- || oheader->sh_type != SHT_NOBITS
- || oheader->sh_size == 0
- || (oheader->sh_info != 0 && oheader->sh_link != 0))
+ if (iheader == NULL)
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 = 0; j < elf_numsections (ibfd); j++)
+ if (oheader->bfd_section != NULL
+ && iheader->bfd_section != NULL
+ && iheader->bfd_section->output_section != NULL
+ && iheader->bfd_section->output_section == oheader->bfd_section)
{
- 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))
- {
- /* 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;
- }
+ /* We have found a connection from the input section to the
+ output section. Attempt to copy the header fields. If
+ this fails then do not try any further sections - there
+ should only be a one-to-one mapping between input and output. */
+ if (! copy_special_section_fields (ibfd, obfd, iheader, oheader, i))
+ j = elf_numsections (ibfd);
+ break;
}
}
+
+ if (j < elf_numsections (ibfd))
+ continue;
+
+ /* That failed. So try to deduce the corresponding input section.
+ 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++)
+ {
+ const Elf_Internal_Shdr * iheader = iheaders[j];
+
+ if (iheader == NULL)
+ continue;
+
+ /* Try matching fields in the input section's header.
+ 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 & ~ SHF_INFO_LINK)
+ == (oheader->sh_flags & ~ SHF_INFO_LINK)
+ && 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))
+ {
+ if (copy_special_section_fields (ibfd, obfd, iheader, oheader, i))
+ break;
+ }
+ }
+
+ if (j == elf_numsections (ibfd) && oheader->sh_type >= SHT_LOOS)
+ {
+ /* Final attempt. Call the backend copy function
+ with a NULL input section. */
+ if (bed->elf_backend_copy_special_section_fields != NULL)
+ bed->elf_backend_copy_special_section_fields (ibfd, obfd, NULL, oheader);
+ }
}
return TRUE;
break;
case SHT_STRTAB:
- case SHT_INIT_ARRAY:
- case SHT_FINI_ARRAY:
- case SHT_PREINIT_ARRAY:
case SHT_NOTE:
case SHT_NOBITS:
case SHT_PROGBITS:
break;
+ case SHT_INIT_ARRAY:
+ case SHT_FINI_ARRAY:
+ case SHT_PREINIT_ARRAY:
+ this_hdr->sh_entsize = bed->s->arch_size / 8;
+ break;
+
case SHT_HASH:
this_hdr->sh_entsize = bed->s->sizeof_hash_entry;
break;
{
this_hdr->sh_flags |= SHF_MERGE;
this_hdr->sh_entsize = asect->entsize;
- if ((asect->flags & SEC_STRINGS) != 0)
- this_hdr->sh_flags |= SHF_STRINGS;
}
+ if ((asect->flags & SEC_STRINGS) != 0)
+ this_hdr->sh_flags |= SHF_STRINGS;
if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL)
this_hdr->sh_flags |= SHF_GROUP;
if ((asect->flags & SEC_THREAD_LOCAL) != 0)
shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr;
/* sh_name was set in prep_headers. */
shstrtab_hdr->sh_type = SHT_STRTAB;
- shstrtab_hdr->sh_flags = 0;
+ shstrtab_hdr->sh_flags = bed->elf_strtab_flags;
shstrtab_hdr->sh_addr = 0;
/* sh_size is set in _bfd_elf_assign_file_positions_for_non_load. */
shstrtab_hdr->sh_entsize = 0;
*sttp = stt;
symstrtab_hdr->sh_size = _bfd_elf_strtab_size (stt);
symstrtab_hdr->sh_type = SHT_STRTAB;
-
- symstrtab_hdr->sh_flags = 0;
+ symstrtab_hdr->sh_flags = bed->elf_strtab_flags;
symstrtab_hdr->sh_addr = 0;
symstrtab_hdr->sh_entsize = 0;
symstrtab_hdr->sh_link = 0;