+/* Copy ELF program header information. */
+
+static bfd_boolean
+copy_elf_program_header (bfd *ibfd, bfd *obfd)
+{
+ Elf_Internal_Ehdr *iehdr;
+ struct elf_segment_map *map;
+ struct elf_segment_map *map_first;
+ struct elf_segment_map **pointer_to_map;
+ Elf_Internal_Phdr *segment;
+ unsigned int i;
+ unsigned int num_segments;
+ bfd_boolean phdr_included = FALSE;
+
+ iehdr = elf_elfheader (ibfd);
+
+ map_first = NULL;
+ pointer_to_map = &map_first;
+
+ num_segments = elf_elfheader (ibfd)->e_phnum;
+ for (i = 0, segment = elf_tdata (ibfd)->phdr;
+ i < num_segments;
+ i++, segment++)
+ {
+ asection *section;
+ unsigned int section_count;
+ bfd_size_type amt;
+ Elf_Internal_Shdr *this_hdr;
+
+ /* FIXME: Do we need to copy PT_NULL segment? */
+ if (segment->p_type == PT_NULL)
+ continue;
+
+ /* Compute how many sections are in this segment. */
+ for (section = ibfd->sections, section_count = 0;
+ section != NULL;
+ section = section->next)
+ {
+ this_hdr = &(elf_section_data(section)->this_hdr);
+ if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
+ section_count++;
+ }
+
+ /* Allocate a segment map big enough to contain
+ all of the sections we have selected. */
+ amt = sizeof (struct elf_segment_map);
+ if (section_count != 0)
+ amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
+ map = bfd_alloc (obfd, amt);
+ if (map == NULL)
+ return FALSE;
+
+ /* Initialize the fields of the output segment map with the
+ input segment. */
+ map->next = NULL;
+ map->p_type = segment->p_type;
+ map->p_flags = segment->p_flags;
+ map->p_flags_valid = 1;
+ map->p_paddr = segment->p_paddr;
+ map->p_paddr_valid = 1;
+
+ /* Determine if this segment contains the ELF file header
+ and if it contains the program headers themselves. */
+ map->includes_filehdr = (segment->p_offset == 0
+ && segment->p_filesz >= iehdr->e_ehsize);
+
+ map->includes_phdrs = 0;
+ if (! phdr_included || segment->p_type != PT_LOAD)
+ {
+ map->includes_phdrs =
+ (segment->p_offset <= (bfd_vma) iehdr->e_phoff
+ && (segment->p_offset + segment->p_filesz
+ >= ((bfd_vma) iehdr->e_phoff
+ + iehdr->e_phnum * iehdr->e_phentsize)));
+
+ if (segment->p_type == PT_LOAD && map->includes_phdrs)
+ phdr_included = TRUE;
+ }
+
+ if (section_count != 0)
+ {
+ unsigned int isec = 0;
+
+ for (section = ibfd->sections;
+ section != NULL;
+ section = section->next)
+ {
+ this_hdr = &(elf_section_data(section)->this_hdr);
+ if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
+ map->sections[isec++] = section->output_section;
+ }
+ }
+
+ map->count = section_count;
+ *pointer_to_map = map;
+ pointer_to_map = &map->next;
+ }
+
+ elf_tdata (obfd)->segment_map = map_first;
+ return TRUE;
+}
+
+/* Copy private BFD data. This copies or rewrites ELF program header
+ information. */
+
+static bfd_boolean
+copy_private_bfd_data (bfd *ibfd, bfd *obfd)
+{
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return TRUE;
+
+ if (elf_tdata (ibfd)->phdr == NULL)
+ return TRUE;
+
+ if (ibfd->xvec == obfd->xvec)
+ {
+ /* Check if any sections in the input BFD covered by ELF program
+ header are changed. */
+ Elf_Internal_Phdr *segment;
+ asection *section, *osec;
+ unsigned int i, num_segments;
+ Elf_Internal_Shdr *this_hdr;
+
+ /* Initialize the segment mark field. */
+ for (section = obfd->sections; section != NULL;
+ section = section->next)
+ section->segment_mark = FALSE;
+
+ num_segments = elf_elfheader (ibfd)->e_phnum;
+ for (i = 0, segment = elf_tdata (ibfd)->phdr;
+ i < num_segments;
+ i++, segment++)
+ {
+ for (section = ibfd->sections;
+ section != NULL; section = section->next)
+ {
+ /* We mark the output section so that we know it comes
+ from the input BFD. */
+ osec = section->output_section;
+ if (osec)
+ osec->segment_mark = TRUE;
+
+ /* Check if this section is covered by the segment. */
+ this_hdr = &(elf_section_data(section)->this_hdr);
+ if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
+ {
+ /* FIXME: Check if its output section is changed or
+ removed. What else do we need to check? */
+ if (osec == NULL
+ || section->flags != osec->flags
+ || section->lma != osec->lma
+ || section->vma != osec->vma
+ || section->size != osec->size
+ || section->rawsize != osec->rawsize
+ || section->alignment_power != osec->alignment_power)
+ goto rewrite;
+ }
+ }
+ }
+
+ /* Check to see if any output section doesn't come from the
+ input BFD. */
+ for (section = obfd->sections; section != NULL;
+ section = section->next)
+ {
+ if (section->segment_mark == FALSE)
+ goto rewrite;
+ else
+ section->segment_mark = FALSE;
+ }
+
+ return copy_elf_program_header (ibfd, obfd);
+ }
+
+rewrite:
+ return rewrite_elf_program_header (ibfd, obfd);
+}
+
+/* Initialize private output section information from input section. */
+
+bfd_boolean
+_bfd_elf_init_private_section_data (bfd *ibfd,
+ asection *isec,
+ bfd *obfd,
+ asection *osec,
+ struct bfd_link_info *link_info)
+
+{
+ Elf_Internal_Shdr *ihdr, *ohdr;
+ bfd_boolean need_group = link_info == NULL || link_info->relocatable;
+
+ if (ibfd->xvec->flavour != bfd_target_elf_flavour
+ || obfd->xvec->flavour != bfd_target_elf_flavour)
+ return TRUE;
+
+ /* Don't copy the output ELF section type from input if the
+ output BFD section flags has been set to something different.
+ elf_fake_sections will set ELF section type based on BFD
+ section flags. */
+ if (osec->flags == isec->flags || !osec->flags)
+ elf_section_type (osec) = elf_section_type (isec);
+
+ /* Set things up for objcopy and relocatable link. The output
+ SHT_GROUP section will have its elf_next_in_group pointing back
+ to the input group members. Ignore linker created group section.
+ See elfNN_ia64_object_p in elfxx-ia64.c. */
+
+ if (need_group)
+ {
+ if (elf_sec_group (isec) == NULL
+ || (elf_sec_group (isec)->flags & SEC_LINKER_CREATED) == 0)
+ {
+ if (elf_section_flags (isec) & SHF_GROUP)
+ elf_section_flags (osec) |= SHF_GROUP;
+ elf_next_in_group (osec) = elf_next_in_group (isec);
+ elf_group_name (osec) = elf_group_name (isec);
+ }
+ }
+
+ ihdr = &elf_section_data (isec)->this_hdr;
+
+ /* We need to handle elf_linked_to_section for SHF_LINK_ORDER. We
+ don't use the output section of the linked-to section since it
+ may be NULL at this point. */
+ if ((ihdr->sh_flags & SHF_LINK_ORDER) != 0)
+ {
+ ohdr = &elf_section_data (osec)->this_hdr;
+ ohdr->sh_flags |= SHF_LINK_ORDER;
+ elf_linked_to_section (osec) = elf_linked_to_section (isec);
+ }
+
+ osec->use_rela_p = isec->use_rela_p;
+
+ return TRUE;
+}
+