+ 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;
+
+ iehdr = elf_elfheader (ibfd);
+
+ mfirst = NULL;
+ pm = &mfirst;
+
+ num_segments = elf_elfheader (ibfd)->e_phnum;
+
+#define IS_CONTAINED_BY(addr, len, bottom, phdr) \
+ ((addr) >= (bottom) \
+ && ( ((addr) + (len)) <= ((bottom) + (phdr)->p_memsz) \
+ || ((addr) + (len)) <= ((bottom) + (phdr)->p_filesz)))
+
+ /* Special case: corefile "NOTE" section containing regs, prpsinfo etc. */
+
+#define IS_COREFILE_NOTE(p, s) \
+ (p->p_type == PT_NOTE \
+ && bfd_get_format (ibfd) == bfd_core \
+ && s->vma == 0 && s->lma == 0 \
+ && (bfd_vma) s->filepos >= p->p_offset \
+ && (bfd_vma) s->filepos + s->_raw_size \
+ <= p->p_offset + p->p_filesz)
+
+ /* The complicated case when p_vaddr is 0 is to handle the Solaris
+ linker, which generates a PT_INTERP section with p_vaddr and
+ p_memsz set to 0. */
+
+#define IS_SOLARIS_PT_INTERP(p, s) \
+ (p->p_vaddr == 0 \
+ && p->p_filesz > 0 \
+ && (s->flags & SEC_HAS_CONTENTS) != 0 \
+ && s->_raw_size > 0 \
+ && (bfd_vma) s->filepos >= p->p_offset \
+ && ((bfd_vma) s->filepos + s->_raw_size \
+ <= p->p_offset + p->p_filesz))
+
+ /* Scan through the segments specified in the program header
+ of the input BFD. */
+ for (i = 0, p = elf_tdata (ibfd)->phdr; i < num_segments; i++, p++)
+ {
+ unsigned int csecs;
+ asection *s;
+ asection **sections;
+ asection *os;
+ unsigned int isec;
+ bfd_vma matching_lma;
+ bfd_vma suggested_lma;
+ unsigned int j;
+
+ /* For each section in the input BFD, decide if it should be
+ included in the current segment. A section will be included
+ if it is within the address space of the segment, and it is
+ an allocated segment, and there is an output section
+ associated with it. */
+ csecs = 0;
+ for (s = ibfd->sections; s != NULL; s = s->next)
+ if (s->output_section != NULL)
+ {
+ if ((IS_CONTAINED_BY (s->vma, s->_raw_size, p->p_vaddr, p)
+ || IS_SOLARIS_PT_INTERP (p, s))
+ && (s->flags & SEC_ALLOC) != 0)
+ ++csecs;
+ else if (IS_COREFILE_NOTE (p, s))
+ ++csecs;
+ }
+
+ /* Allocate a segment map big enough to contain all of the
+ sections we have selected. */
+ m = ((struct elf_segment_map *)
+ bfd_alloc (obfd,
+ (sizeof (struct elf_segment_map)
+ + ((size_t) csecs - 1) * sizeof (asection *))));
+ if (m == NULL)
+ return false;
+
+ /* Initialise the fields of the segment map. Default to
+ using the physical address of the segment in the input BFD. */
+ m->next = NULL;
+ m->p_type = p->p_type;
+ m->p_flags = p->p_flags;
+ m->p_flags_valid = 1;
+ m->p_paddr = p->p_paddr;
+ m->p_paddr_valid = 1;
+
+ /* Determine if this segment contains the ELF file header
+ and if it contains the program headers themselves. */
+ m->includes_filehdr = (p->p_offset == 0
+ && p->p_filesz >= iehdr->e_ehsize);
+
+ m->includes_phdrs = 0;
+
+ if (! phdr_included || p->p_type != PT_LOAD)
+ {
+ m->includes_phdrs =
+ (p->p_offset <= (bfd_vma) iehdr->e_phoff
+ && (p->p_offset + p->p_filesz
+ >= ((bfd_vma) iehdr->e_phoff
+ + iehdr->e_phnum * iehdr->e_phentsize)));
+ if (p->p_type == PT_LOAD && m->includes_phdrs)
+ phdr_included = true;
+ }
+
+ if (csecs == 0)
+ {
+ /* Special segments, such as the PT_PHDR segment, may contain
+ no sections, but ordinary, loadable segments should contain
+ something. */
+
+ if (p->p_type == PT_LOAD)
+ _bfd_error_handler
+ (_("%s: warning: Empty loadable segment detected\n"),
+ bfd_get_filename (ibfd));
+
+ m->count = 0;
+ *pm = m;
+ pm = &m->next;
+
+ continue;
+ }
+
+ /* Now scan the sections in the input BFD again and attempt
+ to add their corresponding output sections to the segment map.
+ The problem here is how to handle an output section which has
+ been moved (ie had its LMA changed). There are four possibilities:
+
+ 1. None of the sections have been moved.
+ In this case we can continue to use the segment LMA from the
+ input BFD.
+
+ 2. All of the sections have been moved by the same amount.
+ In this case we can change the segment's LMA to match the LMA
+ of the first section.
+
+ 3. Some of the sections have been moved, others have not.
+ In this case those sections which have not been moved can be
+ placed in the current segment which will have to have its size,
+ and possibly its LMA changed, and a new segment or segments will
+ have to be created to contain the other sections.
+
+ 4. The sections have been moved, but not be the same amount.
+ In this case we can change the segment's LMA to match the LMA
+ of the first section and we will have to create a new segment
+ or segments to contain the other sections.
+
+ In order to save time, we allocate an array to hold the section
+ pointers that we are interested in. As these sections get assigned
+ to a segment, they are removed from this array. */
+
+ sections = (asection **) bfd_malloc (sizeof (asection *) * csecs);
+ if (sections == NULL)
+ return false;
+
+ /* Step One: Scan for segment vs section LMA conflicts.
+ Also add the sections to the section array allocated above.
+ Also add the sections to the current segment. In the common
+ case, where the sections have not been moved, this means that
+ we have completely filled the segment, and there is nothing
+ more to do. */
+
+ isec = 0;
+ matching_lma = false;
+ suggested_lma = 0;
+
+ for (j = 0, s = ibfd->sections; s != NULL; s = s->next)
+ {
+ os = s->output_section;
+
+ if ((((IS_CONTAINED_BY (s->vma, s->_raw_size, p->p_vaddr, p)
+ || IS_SOLARIS_PT_INTERP (p, s))
+ && (s->flags & SEC_ALLOC) != 0)
+ || IS_COREFILE_NOTE (p, s))
+ && os != NULL)
+ {
+ sections[j++] = s;
+
+ /* The Solaris native linker always sets p_paddr to 0.
+ We try to catch that case here, and set it to the
+ correct value. */
+ if (p->p_paddr == 0
+ && p->p_vaddr != 0
+ && isec == 0
+ && os->lma != 0
+ && (os->vma == (p->p_vaddr
+ + (m->includes_filehdr
+ ? iehdr->e_ehsize
+ : 0)
+ + (m->includes_phdrs
+ ? iehdr->e_phnum * iehdr->e_phentsize
+ : 0))))
+ m->p_paddr = p->p_vaddr;
+
+ /* Match up the physical address of the segment with the
+ LMA address of the output section. */
+ if (IS_CONTAINED_BY (os->lma, os->_raw_size, m->p_paddr, p)
+ || IS_COREFILE_NOTE (p, s))
+ {
+ if (matching_lma == 0)
+ matching_lma = os->lma;
+
+ /* We assume that if the section fits within the segment
+ that it does not overlap any other section within that
+ segment. */
+ m->sections[isec++] = os;
+ }
+ else if (suggested_lma == 0)
+ suggested_lma = os->lma;
+ }
+ }
+
+ BFD_ASSERT (j == csecs);
+
+ /* Step Two: Adjust the physical address of the current segment,
+ if necessary. */
+ if (isec == csecs)
+ {
+ /* All of the sections fitted within the segment as currently
+ specified. This is the default case. Add the segment to
+ the list of built segments and carry on to process the next
+ program header in the input BFD. */
+ m->count = csecs;
+ *pm = m;
+ pm = &m->next;
+
+ free (sections);
+ continue;
+ }
+ else if (matching_lma != 0)
+ {
+ /* At least one section fits inside the current segment.
+ Keep it, but modify its physical address to match the
+ LMA of the first section that fitted. */
+
+ m->p_paddr = matching_lma;
+ }
+ else
+ {
+ /* None of the sections fitted inside the current segment.
+ Change the current segment's physical address to match
+ the LMA of the first section. */
+
+ m->p_paddr = suggested_lma;
+ }
+
+ /* Step Three: Loop over the sections again, this time assigning
+ those that fit to the current segment and remvoing them from the
+ sections array; but making sure not to leave large gaps. Once all
+ possible sections have been assigned to the current segment it is
+ added to the list of built segments and if sections still remain
+ to be assigned, a new segment is constructed before repeating
+ the loop. */
+ isec = 0;
+ do
+ {
+ m->count = 0;
+ suggested_lma = 0;
+
+ /* Fill the current segment with sections that fit. */
+ for (j = 0; j < csecs; j++)
+ {
+ s = sections[j];
+
+ if (s == NULL)
+ continue;
+
+ os = s->output_section;
+
+ if (IS_CONTAINED_BY (os->lma, os->_raw_size, m->p_paddr, p)
+ || IS_COREFILE_NOTE (p, s))
+ {
+ if (m->count == 0)
+ {
+ /* If the first section in a segment does not start at
+ the beginning of the segment, then something is wrong. */
+ if (os->lma != m->p_paddr)
+ abort ();
+ }
+ else
+ {
+ asection * prev_sec;
+ bfd_vma maxpagesize;
+
+ prev_sec = m->sections[m->count - 1];
+ maxpagesize = get_elf_backend_data (obfd)->maxpagesize;
+
+ /* If the gap between the end of the previous section
+ and the start of this section is more than maxpagesize
+ then we need to start a new segment. */
+ if (BFD_ALIGN (prev_sec->lma + prev_sec->_raw_size, maxpagesize)
+ < BFD_ALIGN (os->lma, maxpagesize))
+ {
+ if (suggested_lma == 0)
+ suggested_lma = os->lma;
+
+ continue;
+ }
+ }
+
+ m->sections[m->count++] = os;
+ ++isec;
+ sections[j] = NULL;
+ }
+ else if (suggested_lma == 0)
+ suggested_lma = os->lma;
+ }
+
+ BFD_ASSERT (m->count > 0);
+
+ /* Add the current segment to the list of built segments. */
+ *pm = m;
+ pm = &m->next;
+
+ if (isec < csecs)
+ {
+ /* We still have not allocated all of the sections to
+ segments. Create a new segment here, initialise it
+ and carry on looping. */
+
+ m = ((struct elf_segment_map *)
+ bfd_alloc (obfd,
+ (sizeof (struct elf_segment_map)
+ + ((size_t) csecs - 1) * sizeof (asection *))));
+ if (m == NULL)
+ return false;
+
+ /* Initialise the fields of the segment map. Set the physical
+ physical address to the LMA of the first section that has
+ not yet been assigned. */
+
+ m->next = NULL;
+ m->p_type = p->p_type;
+ m->p_flags = p->p_flags;
+ m->p_flags_valid = 1;
+ m->p_paddr = suggested_lma;
+ m->p_paddr_valid = 1;
+ m->includes_filehdr = 0;
+ m->includes_phdrs = 0;
+ }
+ }
+ while (isec < csecs);
+
+ free (sections);
+ }
+
+ /* The Solaris linker creates program headers in which all the
+ p_paddr fields are zero. When we try to objcopy or strip such a
+ file, we get confused. Check for this case, and if we find it
+ reset the p_paddr_valid fields. */
+ for (m = mfirst; m != NULL; m = m->next)
+ if (m->p_paddr != 0)
+ break;
+ if (m == NULL)
+ {
+ for (m = mfirst; m != NULL; m = m->next)
+ m->p_paddr_valid = 0;
+ }
+
+ elf_tdata (obfd)->segment_map = mfirst;
+
+#if 0
+ /* Final Step: Sort the segments into ascending order of physical address. */
+ if (mfirst != NULL)
+ {
+ struct elf_segment_map* prev;
+
+ prev = mfirst;
+ for (m = mfirst->next; m != NULL; prev = m, m = m->next)
+ {
+ /* Yes I know - its a bubble sort....*/
+ if (m->next != NULL && (m->next->p_paddr < m->p_paddr))
+ {
+ /* swap m and m->next */
+ prev->next = m->next;
+ m->next = m->next->next;
+ prev->next->next = m;
+
+ /* restart loop. */
+ m = mfirst;
+ }
+ }
+ }
+#endif
+
+#undef IS_CONTAINED_BY
+#undef IS_SOLARIS_PT_INTERP
+#undef IS_COREFILE_NOTE
+ return true;
+}
+
+/* Copy private section information. This copies over the entsize
+ field, and sometimes the info field. */
+
+boolean
+_bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)
+ bfd *ibfd;
+ asection *isec;
+ bfd *obfd;
+ asection *osec;
+{
+ Elf_Internal_Shdr *ihdr, *ohdr;
+
+ if (ibfd->xvec->flavour != bfd_target_elf_flavour
+ || obfd->xvec->flavour != bfd_target_elf_flavour)
+ return true;
+
+ /* Copy over private BFD data if it has not already been copied.
+ This must be done here, rather than in the copy_private_bfd_data
+ entry point, because the latter is called after the section
+ contents have been set, which means that the program headers have
+ already been worked out. */
+ if (elf_tdata (obfd)->segment_map == NULL
+ && elf_tdata (ibfd)->phdr != NULL)
+ {
+ asection *s;
+
+ /* Only set up the segments if there are no more SEC_ALLOC
+ sections. FIXME: This won't do the right thing if objcopy is
+ used to remove the last SEC_ALLOC section, since objcopy
+ won't call this routine in that case. */
+ for (s = isec->next; s != NULL; s = s->next)
+ if ((s->flags & SEC_ALLOC) != 0)
+ break;
+ if (s == NULL)
+ {
+ if (! copy_private_bfd_data (ibfd, obfd))
+ return false;
+ }
+ }
+
+ ihdr = &elf_section_data (isec)->this_hdr;
+ ohdr = &elf_section_data (osec)->this_hdr;
+
+ ohdr->sh_entsize = ihdr->sh_entsize;
+
+ if (ihdr->sh_type == SHT_SYMTAB
+ || ihdr->sh_type == SHT_DYNSYM
+ || ihdr->sh_type == SHT_GNU_verneed
+ || ihdr->sh_type == SHT_GNU_verdef)
+ ohdr->sh_info = ihdr->sh_info;
+
+ elf_section_data (osec)->use_rela_p
+ = elf_section_data (isec)->use_rela_p;
+
+ return true;
+}
+
+/* Copy private symbol information. If this symbol is in a section
+ which we did not map into a BFD section, try to map the section
+ index correctly. We use special macro definitions for the mapped
+ section indices; these definitions are interpreted by the
+ swap_out_syms function. */
+
+#define MAP_ONESYMTAB (SHN_LORESERVE - 1)
+#define MAP_DYNSYMTAB (SHN_LORESERVE - 2)
+#define MAP_STRTAB (SHN_LORESERVE - 3)
+#define MAP_SHSTRTAB (SHN_LORESERVE - 4)
+
+boolean
+_bfd_elf_copy_private_symbol_data (ibfd, isymarg, obfd, osymarg)
+ bfd *ibfd;
+ asymbol *isymarg;
+ bfd *obfd;
+ asymbol *osymarg;
+{
+ elf_symbol_type *isym, *osym;
+
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return true;
+
+ isym = elf_symbol_from (ibfd, isymarg);
+ osym = elf_symbol_from (obfd, osymarg);
+
+ if (isym != NULL
+ && osym != NULL
+ && bfd_is_abs_section (isym->symbol.section))
+ {
+ unsigned int shndx;
+
+ shndx = isym->internal_elf_sym.st_shndx;
+ if (shndx == elf_onesymtab (ibfd))
+ shndx = MAP_ONESYMTAB;
+ else if (shndx == elf_dynsymtab (ibfd))
+ shndx = MAP_DYNSYMTAB;
+ else if (shndx == elf_tdata (ibfd)->strtab_section)
+ shndx = MAP_STRTAB;
+ else if (shndx == elf_tdata (ibfd)->shstrtab_section)
+ shndx = MAP_SHSTRTAB;
+ osym->internal_elf_sym.st_shndx = shndx;
+ }
+
+ return true;
+}
+
+/* Swap out the symbols. */
+
+static boolean
+swap_out_syms (abfd, sttp, relocatable_p)
+ bfd *abfd;
+ struct bfd_strtab_hash **sttp;
+ int relocatable_p;
+{
+ struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ if (!elf_map_symbols (abfd))