+ failed = false;
+ bfd_map_over_sections (abfd, bed->s->write_relocs, &failed);
+ if (failed)
+ return false;
+
+ _bfd_elf_assign_file_positions_for_relocs (abfd);
+
+ /* After writing the headers, we need to write the sections too... */
+ for (count = 1; count < i_ehdrp->e_shnum; count++)
+ {
+ if (bed->elf_backend_section_processing)
+ (*bed->elf_backend_section_processing) (abfd, i_shdrp[count]);
+ if (i_shdrp[count]->contents)
+ {
+ if (bfd_seek (abfd, i_shdrp[count]->sh_offset, SEEK_SET) != 0
+ || (bfd_write (i_shdrp[count]->contents, i_shdrp[count]->sh_size,
+ 1, abfd)
+ != i_shdrp[count]->sh_size))
+ return false;
+ }
+ }
+
+ /* Write out the section header names. */
+ if (bfd_seek (abfd, elf_tdata (abfd)->shstrtab_hdr.sh_offset, SEEK_SET) != 0
+ || ! _bfd_stringtab_emit (abfd, elf_shstrtab (abfd)))
+ return false;
+
+ if (bed->elf_backend_final_write_processing)
+ (*bed->elf_backend_final_write_processing) (abfd,
+ elf_tdata (abfd)->linker);
+
+ return bed->s->write_shdrs_and_ehdr (abfd);
+}
+
+boolean
+_bfd_elf_write_corefile_contents (abfd)
+ bfd *abfd;
+{
+ /* Hopefully this can be done just like an object file. */
+ return _bfd_elf_write_object_contents (abfd);
+}
+/* given a section, search the header to find them... */
+int
+_bfd_elf_section_from_bfd_section (abfd, asect)
+ bfd *abfd;
+ struct sec *asect;
+{
+ struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd);
+ int index;
+ Elf_Internal_Shdr *hdr;
+ int maxindex = elf_elfheader (abfd)->e_shnum;
+
+ for (index = 0; index < maxindex; index++)
+ {
+ hdr = i_shdrp[index];
+ if (hdr->bfd_section == asect)
+ return index;
+ }
+
+ if (bed->elf_backend_section_from_bfd_section)
+ {
+ for (index = 0; index < maxindex; index++)
+ {
+ int retval;
+
+ hdr = i_shdrp[index];
+ retval = index;
+ if ((*bed->elf_backend_section_from_bfd_section)
+ (abfd, hdr, asect, &retval))
+ return retval;
+ }
+ }
+
+ if (bfd_is_abs_section (asect))
+ return SHN_ABS;
+ if (bfd_is_com_section (asect))
+ return SHN_COMMON;
+ if (bfd_is_und_section (asect))
+ return SHN_UNDEF;
+
+ bfd_set_error (bfd_error_nonrepresentable_section);
+
+ return -1;
+}
+
+/* Given a BFD symbol, return the index in the ELF symbol table, or -1
+ on error. */
+
+int
+_bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr)
+ bfd *abfd;
+ asymbol **asym_ptr_ptr;
+{
+ asymbol *asym_ptr = *asym_ptr_ptr;
+ int idx;
+ flagword flags = asym_ptr->flags;
+
+ /* When gas creates relocations against local labels, it creates its
+ own symbol for the section, but does put the symbol into the
+ symbol chain, so udata is 0. When the linker is generating
+ relocatable output, this section symbol may be for one of the
+ input sections rather than the output section. */
+ if (asym_ptr->udata.i == 0
+ && (flags & BSF_SECTION_SYM)
+ && asym_ptr->section)
+ {
+ int indx;
+
+ if (asym_ptr->section->output_section != NULL)
+ indx = asym_ptr->section->output_section->index;
+ else
+ indx = asym_ptr->section->index;
+ if (elf_section_syms (abfd)[indx])
+ asym_ptr->udata.i = elf_section_syms (abfd)[indx]->udata.i;
+ }
+
+ idx = asym_ptr->udata.i;
+
+ if (idx == 0)
+ {
+ /* This case can occur when using --strip-symbol on a symbol
+ which is used in a relocation entry. */
+ (*_bfd_error_handler)
+ (_("%s: symbol `%s' required but not present"),
+ bfd_get_filename (abfd), bfd_asymbol_name (asym_ptr));
+ bfd_set_error (bfd_error_no_symbols);
+ return -1;
+ }
+
+#if DEBUG & 4
+ {
+ fprintf (stderr,
+ _("elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n"),
+ (long) asym_ptr, asym_ptr->name, idx, flags,
+ elf_symbol_flags (flags));
+ fflush (stderr);
+ }
+#endif
+
+ return idx;
+}
+
+/* Copy private BFD data. This copies any program header information. */
+
+static boolean
+copy_private_bfd_data (ibfd, obfd)
+ bfd *ibfd;
+ bfd *obfd;
+{
+ Elf_Internal_Ehdr *iehdr;
+ struct elf_segment_map *mfirst;
+ struct elf_segment_map **pm;
+ struct elf_segment_map *m;
+ Elf_Internal_Phdr *p;
+ unsigned int i;
+ unsigned int num_segments;
+ boolean phdr_included = false;
+
+ 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;