Changes to support ELF strip and objcopy on dynamically linked
authorIan Lance Taylor <ian@airs.com>
Sun, 5 Jun 1994 20:00:42 +0000 (20:00 +0000)
committerIan Lance Taylor <ian@airs.com>
Sun, 5 Jun 1994 20:00:42 +0000 (20:00 +0000)
files.
* elfcode.h (elf_fake_sections): Add prototype.
(bfd_section_from_shdr): Make a BFD section from an SHT_HASH
section, and from an SHT_DYNSYM section, and from the dynamic
string table section.
(elf_object_p): Set D_PAGED if there is a program header.
(elf_make_sections): Remove.
(fix_up_strtabs): Remove.
(elf_fake_sections): Rewrite.  Now sets sh_entsize.
(assign_section_numbers): Rewrite.  Now sets sh_link and sh_info
for all sections.
(elf_compute_section_file_positions):  Don't call obsolete
functions elf_make_sections or fix_up_strtabs.
(swap_out_syms): Set sh_addralign to FILE_ALIGN rather than 4.
(NAME(bfd_elf,write_object_contents)): Permit writing DYNAMIC
objects.
(elf_section_from_bfd_section): Treat SHT_DYNSYM like other normal
sections.  If an SHT_REL or SHT_RELA section is allocated or uses
an unusual symbol table, permit a BFD section to map to it.
Permit most SHT_STRTAB sections to have a BFD section mapped to
them.
(elf_bfd_final_link): Don't set sh_link, sh_info or sh_entsize
fields of dynamic sections here; do it in assign_section_numbers.
* elf32-target.h, elf64-target.h: Add D_PAGED to permitted object
flags.

bfd/ChangeLog
bfd/elf32-target.h
bfd/elf64-target.h
bfd/elfcode.h

index eae173b81f3ea8a2ee5b76571d3cf5ffff2d97d3..5102ba6ce537a9d48aacd5626d297612bb21ab2f 100644 (file)
@@ -1,5 +1,32 @@
 Sun Jun  5 15:02:30 1994  Ian Lance Taylor  (ian@tweedledumb.cygnus.com)
 
+       Changes to support ELF strip and objcopy on dynamically linked
+       files.
+       * elfcode.h (elf_fake_sections): Add prototype.
+       (bfd_section_from_shdr): Make a BFD section from an SHT_HASH
+       section, and from an SHT_DYNSYM section, and from the dynamic
+       string table section.
+       (elf_object_p): Set D_PAGED if there is a program header.
+       (elf_make_sections): Remove.
+       (fix_up_strtabs): Remove.
+       (elf_fake_sections): Rewrite.  Now sets sh_entsize.
+       (assign_section_numbers): Rewrite.  Now sets sh_link and sh_info
+       for all sections.
+       (elf_compute_section_file_positions):  Don't call obsolete
+       functions elf_make_sections or fix_up_strtabs.
+       (swap_out_syms): Set sh_addralign to FILE_ALIGN rather than 4.
+       (NAME(bfd_elf,write_object_contents)): Permit writing DYNAMIC
+       objects.
+       (elf_section_from_bfd_section): Treat SHT_DYNSYM like other normal
+       sections.  If an SHT_REL or SHT_RELA section is allocated or uses
+       an unusual symbol table, permit a BFD section to map to it.
+       Permit most SHT_STRTAB sections to have a BFD section mapped to
+       them.
+       (elf_bfd_final_link): Don't set sh_link, sh_info or sh_entsize
+       fields of dynamic sections here; do it in assign_section_numbers.
+       * elf32-target.h, elf64-target.h: Add D_PAGED to permitted object
+       flags.
+
        * elf.c (_bfd_elf_make_section_from_shdr): Only set SEC_DATA if
        SEC_LOAD is set, rather than checking SEC_ALLOC.
 
index ae318767b7e0993bf1cc745513eece635d9855a0..6192ad53a2d2bd4868776c8cfb6fcc340c022a3f 100644 (file)
@@ -194,7 +194,7 @@ bfd_target TARGET_BIG_SYM =
 
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS |
-   DYNAMIC | WP_TEXT),
+   DYNAMIC | WP_TEXT | D_PAGED),
   
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY |
@@ -282,7 +282,7 @@ bfd_target TARGET_LITTLE_SYM =
 
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS |
-   DYNAMIC | WP_TEXT),
+   DYNAMIC | WP_TEXT | D_PAGED),
   
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY |
index 4730386968d3a09c939092af3c5f70b17180a8a6..dbab77d7a9f350e6380ba1fb86d787f0c8018937 100644 (file)
@@ -197,7 +197,7 @@ bfd_target TARGET_BIG_SYM =
 
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS |
-   DYNAMIC | WP_TEXT),
+   DYNAMIC | WP_TEXT | D_PAGED),
   
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY |
@@ -285,7 +285,7 @@ bfd_target TARGET_LITTLE_SYM =
 
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS |
-   DYNAMIC | WP_TEXT),
+   DYNAMIC | WP_TEXT | D_PAGED),
   
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY |
index 21deffdf167af71ded7f551c97ac83aa09b9daa6..28befbdf2052ad44426e4d9448ee728b40ebb302 100644 (file)
@@ -145,6 +145,7 @@ static int elf_symbol_from_bfd_symbol PARAMS ((bfd *,
 static boolean elf_compute_section_file_positions
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean prep_headers PARAMS ((bfd *));
+static void elf_fake_sections PARAMS ((bfd *, asection *, PTR));
 static boolean assign_section_numbers PARAMS ((bfd *));
 static file_ptr align_file_position PARAMS ((file_ptr));
 static file_ptr assign_file_position_for_section
@@ -520,6 +521,7 @@ bfd_section_from_shdr (abfd, shindex)
     case SHT_PROGBITS: /* Normal section with contents.  */
     case SHT_DYNAMIC:  /* Dynamic linking information.  */
     case SHT_NOBITS:   /* .bss section.  */
+    case SHT_HASH:     /* .hash section.  */
       return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
 
     case SHT_SYMTAB:           /* A symbol table */
@@ -544,7 +546,10 @@ bfd_section_from_shdr (abfd, shindex)
       elf_tdata (abfd)->dynsymtab_hdr = *hdr;
       elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->dynsymtab_hdr;
       abfd->flags |= HAS_SYMS;
-      return true;
+
+      /* Besides being a symbol table, we also treat this as a regular
+        section, so that objcopy can handle it.  */
+      return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
 
     case SHT_STRTAB:           /* A string table */
       if (hdr->rawdata != NULL)
@@ -569,14 +574,18 @@ bfd_section_from_shdr (abfd, shindex)
                if (elf_onesymtab (abfd) == i)
                  {
                    elf_tdata (abfd)->strtab_hdr = *hdr;
-                   elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->strtab_hdr;
+                   elf_elfsections (abfd)[shindex] =
+                     &elf_tdata (abfd)->strtab_hdr;
                    return true;
                  }
                if (elf_dynsymtab (abfd) == i)
                  {
                    elf_tdata (abfd)->dynstrtab_hdr = *hdr;
-                   elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->dynstrtab_hdr;
-                   return true;
+                   elf_elfsections (abfd)[shindex] =
+                     &elf_tdata (abfd)->dynstrtab_hdr;
+                   /* We also treat this as a regular section, so
+                      that objcopy can handle it.  */
+                   break;
                  }
 #if 0 /* Not handling other string tables specially right now.  */
                hdr2 = elf_elfsections (abfd)[i];       /* in case it moved */
@@ -649,13 +658,6 @@ bfd_section_from_shdr (abfd, shindex)
       }
       break;
 
-    case SHT_HASH:
-#if 0
-      fprintf (stderr, "Dynamic Linking sections not yet supported.\n");
-      BFD_FAIL ();
-#endif
-      break;
-
     case SHT_NOTE:
 #if 0
       fprintf (stderr, "Note Sections not yet supported.\n");
@@ -926,13 +928,14 @@ elf_object_p (abfd)
        }
     }
 
-  /* Set the flags and architecture before calling the backend so that
-     it can override them.  */
   if (i_ehdrp->e_type == ET_EXEC)
     abfd->flags |= EXEC_P;
   else if (i_ehdrp->e_type == ET_DYN)
     abfd->flags |= DYNAMIC;
 
+  if (i_ehdrp->e_phnum > 0)
+    abfd->flags |= D_PAGED;
+
   if (! bfd_default_set_arch_mach (abfd, ebd->arch, 0))
     goto got_no_match;
 
@@ -1036,78 +1039,6 @@ elf_symbol_from (ignore_abfd, symbol)
   return (elf_symbol_type *) symbol;
 }
 
-/* Create ELF output from BFD sections.
-
-   Essentially, just create the section header and forget about the program
-   header for now.  */
-
-static void
-elf_make_sections (abfd, asect, obj)
-     bfd *abfd;
-     asection *asect;
-     PTR obj;
-{
-  /* most of what is in bfd_shdr_from_section goes in here... */
-  /* and all of these sections generate at *least* one ELF section. */
-  Elf_Internal_Shdr *this_hdr;
-  this_hdr = &elf_section_data (asect)->this_hdr;
-
-  this_hdr->sh_addr = asect->vma;
-  this_hdr->sh_size = asect->_raw_size;
-  /* contents already set by elf_set_section_contents */
-
-  if (asect->flags & SEC_RELOC)
-    {
-      /* emit a reloc section, and thus strtab and symtab... */
-      Elf_Internal_Shdr *rela_hdr;
-      int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
-
-      rela_hdr = &elf_section_data (asect)->rel_hdr;
-
-      /* orelocation has the data, reloc_count has the count... */
-      if (use_rela_p)
-       {
-         rela_hdr->sh_type = SHT_RELA;
-         rela_hdr->sh_entsize = sizeof (Elf_External_Rela);
-       }
-      else
-       /* REL relocations */
-       {
-         rela_hdr->sh_type = SHT_REL;
-         rela_hdr->sh_entsize = sizeof (Elf_External_Rel);
-       }
-      rela_hdr->sh_flags = 0;
-      rela_hdr->sh_addr = 0;
-      rela_hdr->sh_offset = 0;
-
-      /* FIXME: Systems I've checked use an alignment of 4, but it is
-        possible that some systems use a different alignment.  */
-      rela_hdr->sh_addralign = 4;
-
-      rela_hdr->size = 0;
-    }
-  if (asect->flags & SEC_ALLOC)
-    {
-      this_hdr->sh_flags |= SHF_ALLOC;
-      if (asect->flags & SEC_LOAD)
-       {
-         /* @@ Do something with sh_type? */
-       }
-    }
-  else
-    {
-      /* If this section is not part of the program image during
-        execution, leave the address fields at 0.  */
-      this_hdr->sh_addr = 0;
-      asect->vma = 0;
-    }
-  if (!(asect->flags & SEC_READONLY))
-    this_hdr->sh_flags |= SHF_WRITE;
-
-  if (asect->flags & SEC_CODE)
-    this_hdr->sh_flags |= SHF_EXECINSTR;
-}
-
 void
 write_relocs (abfd, sec, xxx)
      bfd *abfd;
@@ -1211,96 +1142,97 @@ write_relocs (abfd, sec, xxx)
     }
 }
 
-static void
-fix_up_strtabs (abfd, asect, obj)
-     bfd *abfd;
-     asection *asect;
-     PTR obj;
-{
-  Elf_Internal_Shdr *this_hdr = &elf_section_data (asect)->this_hdr;
-  int this_idx = elf_section_data (asect)->this_idx;
-
-  /* @@ Check flags!  */
-  if (!strncmp (asect->name, ".stab", 5)
-      && !strcmp ("str", asect->name + strlen (asect->name) - 3))
-    {
-      size_t len = strlen (asect->name) + 1;
-      char *s = (char *) malloc (len);
-      if (s == NULL)
-       /* FIXME: Should deal more gracefully with errors.  */
-       abort ();
-      strcpy (s, asect->name);
-      s[len - 4] = 0;
-      asect = bfd_get_section_by_name (abfd, s);
-      free (s);
-      if (!asect)
-       abort ();
-      elf_section_data (asect)->this_hdr.sh_link = this_idx;
-      /* @@ Assuming 32 bits!  */
-      elf_section_data (asect)->this_hdr.sh_entsize = 0xc;
-
-      this_hdr->sh_type = SHT_STRTAB;
-    }
-}
+/* Set up an ELF internal section header for a section.  */
 
+/*ARGSUSED*/
 static void
-elf_fake_sections (abfd, asect, obj)
+elf_fake_sections (abfd, asect, ignore)
      bfd *abfd;
      asection *asect;
-     PTR obj;
+     PTR ignore;
 {
-  /* most of what is in bfd_shdr_from_section goes in here... */
-  /* and all of these sections generate at *least* one ELF section. */
-
   Elf_Internal_Shdr *this_hdr;
+
   this_hdr = &elf_section_data (asect)->this_hdr;
-  this_hdr->sh_name =
-    bfd_add_to_strtab (abfd, elf_shstrtab (abfd), asect->name);
+
+  this_hdr->sh_name = bfd_add_to_strtab (abfd, elf_shstrtab (abfd),
+                                        asect->name);
   if (this_hdr->sh_name == (unsigned long) -1)
     abort (); /* FIXME */
-  /* We need to log the type *now* so that elf_section_from_bfd_section
-     can find us... have to set rawdata too. */
-  this_hdr->rawdata = (void *) asect;
+
+  this_hdr->sh_flags = 0;
+  if ((asect->flags & SEC_ALLOC) != 0)
+    this_hdr->sh_addr = asect->vma;
+  else
+    this_hdr->sh_addr = 0;
+  this_hdr->sh_offset = 0;
+  this_hdr->sh_size = asect->_raw_size;
+  this_hdr->sh_link = 0;
+  this_hdr->sh_info = 0;
   this_hdr->sh_addralign = 1 << asect->alignment_power;
+  this_hdr->sh_entsize = 0;
+
+  this_hdr->rawdata = (PTR) asect;
+  this_hdr->contents = NULL;
+  this_hdr->size = 0;
 
   /* FIXME: This should not be based on section names.  */
   if (strcmp (asect->name, ".dynstr") == 0)
     this_hdr->sh_type = SHT_STRTAB;
   else if (strcmp (asect->name, ".hash") == 0)
-    this_hdr->sh_type = SHT_HASH;
+    {
+      this_hdr->sh_type = SHT_HASH;
+      this_hdr->sh_entsize = ARCH_SIZE / 8;
+    }
   else if (strcmp (asect->name, ".dynsym") == 0)
-    this_hdr->sh_type = SHT_DYNSYM;
+    {
+      this_hdr->sh_type = SHT_DYNSYM;
+      this_hdr->sh_entsize = sizeof (Elf_External_Sym);
+    }
   else if (strcmp (asect->name, ".dynamic") == 0)
-    this_hdr->sh_type = SHT_DYNAMIC;
+    {
+      this_hdr->sh_type = SHT_DYNAMIC;
+      this_hdr->sh_entsize = sizeof (Elf_External_Dyn);
+    }
   else if (strncmp (asect->name, ".rel.", 5) == 0)
-    this_hdr->sh_type = SHT_REL;
+    {
+      this_hdr->sh_type = SHT_REL;
+      this_hdr->sh_entsize = sizeof (Elf_External_Rel);
+    }
   else if (strncmp (asect->name, ".rela.", 6) == 0)
-    this_hdr->sh_type = SHT_RELA;
-  else if ((asect->flags & SEC_ALLOC) && (asect->flags & SEC_LOAD))
+    {
+      this_hdr->sh_type = SHT_RELA;
+      this_hdr->sh_entsize = sizeof (Elf_External_Rela);
+    }
+  else if (strcmp (asect->name, ".note") == 0)
+    this_hdr->sh_type = SHT_NOTE;
+  else if (strncmp (asect->name, ".stab", 5) == 0
+          && strcmp (asect->name + strlen (asect->name) - 3, "str") == 0)
+    this_hdr->sh_type = SHT_STRTAB;
+  else if ((asect->flags & SEC_ALLOC) != 0
+          && (asect->flags & SEC_LOAD) != 0)
     this_hdr->sh_type = SHT_PROGBITS;
-  else if ((asect->flags & SEC_ALLOC) && ((asect->flags & SEC_LOAD) == 0))
+  else if ((asect->flags & SEC_ALLOC) != 0
+          && ((asect->flags & SEC_LOAD) == 0))
     {
       BFD_ASSERT (strcmp (asect->name, ".bss") == 0
                  || strcmp (asect->name, ".sbss") == 0);
       this_hdr->sh_type = SHT_NOBITS;
     }
-  /* FIXME I am not sure how to detect a .note section from the flags
-     word of an `asection'.  */
-  else if (!strcmp (asect->name, ".note"))
-    this_hdr->sh_type = SHT_NOTE;
   else
-    this_hdr->sh_type = SHT_PROGBITS;
+    {
+      /* Who knows?  */
+      this_hdr->sh_type = SHT_PROGBITS;
+    }
 
-  this_hdr->sh_flags = 0;
-  this_hdr->sh_addr = 0;
-  this_hdr->sh_size = 0;
-  this_hdr->sh_entsize = 0;
-  this_hdr->sh_info = 0;
-  this_hdr->sh_link = 0;
-  this_hdr->sh_offset = 0;
-  this_hdr->size = 0;
+  if ((asect->flags & SEC_ALLOC) != 0)
+    this_hdr->sh_flags |= SHF_ALLOC;
+  if ((asect->flags & SEC_READONLY) == 0)
+    this_hdr->sh_flags |= SHF_WRITE;
+  if ((asect->flags & SEC_CODE) != 0)
+    this_hdr->sh_flags |= SHF_EXECINSTR;
 
-  /* Now, check for processor-specific section types.  */
+  /* Check for processor-specific section types.  */
   {
     struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
@@ -1308,51 +1240,199 @@ elf_fake_sections (abfd, asect, obj)
       (*bed->elf_backend_fake_sections) (abfd, this_hdr, asect);
   }
 
-  {
-    /* Emit a strtab and symtab, and possibly a reloc section.  */
-    Elf_Internal_Shdr *rela_hdr;
+  /* If the section has relocs, set up a section header for the
+     SHT_REL[A] section.  */
+  if ((asect->flags & SEC_RELOC) != 0)
+    {
+      Elf_Internal_Shdr *rela_hdr;
+      int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
 
-    /* Note that only one symtab is used, so just remember it
-       for now.  */
+      rela_hdr = &elf_section_data (asect)->rel_hdr;
+      rela_hdr->sh_name =
+       bfd_add_2_to_strtab (abfd, elf_shstrtab (abfd),
+                            use_rela_p ? ".rela" : ".rel",
+                            asect->name);
+      rela_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
+      rela_hdr->sh_entsize = (use_rela_p
+                             ? sizeof (Elf_External_Rela)
+                             : sizeof (Elf_External_Rel));
+      rela_hdr->sh_addralign = FILE_ALIGN;
+      rela_hdr->sh_flags = 0;
+      rela_hdr->sh_addr = 0;
+      rela_hdr->sh_size = 0;
+      rela_hdr->sh_offset = 0;
+      rela_hdr->size = 0;
+    }
+}
 
-    if (asect->flags & SEC_RELOC)
-      {
-       int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
+/* Assign all ELF section numbers.  The dummy first section is handled here
+   too.  The link/info pointers for the standard section types are filled
+   in here too, while we're at it.  (Link pointers for .stab sections are
+   not filled in here.)  */
 
-       rela_hdr = &elf_section_data (asect)->rel_hdr;
-       rela_hdr->sh_name =
-         bfd_add_2_to_strtab (abfd, elf_shstrtab (abfd),
-                              use_rela_p ? ".rela" : ".rel",
-                              asect->name);
-       rela_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
-       rela_hdr->sh_entsize = (use_rela_p
-                               ? sizeof (Elf_External_Rela)
-                               : sizeof (Elf_External_Rel));
-
-       rela_hdr->sh_flags = 0;
-       rela_hdr->sh_addr = 0;
-       rela_hdr->sh_size = 0;
-       rela_hdr->sh_offset = 0;
-
-       /* FIXME: Systems I've checked use an alignment of 4, but some
-          systems may use a different alignment.  */
-       rela_hdr->sh_addralign = 4;
-
-       rela_hdr->size = 0;
-      }
-  }
-  if (asect->flags & SEC_ALLOC)
+static boolean
+assign_section_numbers (abfd)
+     bfd *abfd;
+{
+  struct elf_obj_tdata *t = elf_tdata (abfd);
+  asection *sec;
+  unsigned int section_number;
+  Elf_Internal_Shdr **i_shdrp;
+
+  section_number = 1;
+
+  t->shstrtab_section = section_number++;
+  elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section;
+  t->shstrtab_hdr.sh_size = elf_shstrtab (abfd)->length;
+  t->shstrtab_hdr.contents = (PTR) elf_shstrtab (abfd)->tab;
+
+  if (abfd->symcount > 0)
+    {
+      t->symtab_section = section_number++;
+      t->strtab_section = section_number++;
+    }
+
+  for (sec = abfd->sections; sec; sec = sec->next)
+    {
+      struct bfd_elf_section_data *d = elf_section_data (sec);
+
+      d->this_idx = section_number++;
+      if ((sec->flags & SEC_RELOC) == 0)
+       d->rel_idx = 0;
+      else
+       d->rel_idx = section_number++;
+    }
+
+  elf_elfheader (abfd)->e_shnum = section_number;
+
+  /* Set up the list of section header pointers, in agreement with the
+     indices.  */
+  i_shdrp = ((Elf_Internal_Shdr **)
+            bfd_alloc (abfd, section_number * sizeof (Elf_Internal_Shdr *)));
+  if (i_shdrp == NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
+
+  i_shdrp[0] = ((Elf_Internal_Shdr *)
+               bfd_alloc (abfd, sizeof (Elf_Internal_Shdr)));
+  if (i_shdrp[0] == NULL)
+    {
+      bfd_release (abfd, i_shdrp);
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
+  memset (i_shdrp[0], 0, sizeof (Elf_Internal_Shdr));
+
+  elf_elfsections (abfd) = i_shdrp;
+
+  i_shdrp[t->shstrtab_section] = &t->shstrtab_hdr;
+  if (abfd->symcount > 0)
+    {
+      i_shdrp[t->symtab_section] = &t->symtab_hdr;
+      i_shdrp[t->strtab_section] = &t->strtab_hdr;
+      t->symtab_hdr.sh_link = t->strtab_section;
+    }
+  for (sec = abfd->sections; sec; sec = sec->next)
     {
-      this_hdr->sh_flags |= SHF_ALLOC;
-      if (asect->flags & SEC_LOAD)
+      struct bfd_elf_section_data *d = elf_section_data (sec);
+      asection *s;
+      const char *name;
+
+      i_shdrp[d->this_idx] = &d->this_hdr;
+      if (d->rel_idx != 0)
+       i_shdrp[d->rel_idx] = &d->rel_hdr;
+
+      /* Fill in the sh_link and sh_info fields while we're at it.  */
+
+      /* sh_link of a reloc section is the section index of the symbol
+        table.  sh_info is the section index of the section to which
+        the relocation entries apply.  */
+      if (d->rel_idx != 0)
+       {
+         d->rel_hdr.sh_link = t->symtab_section;
+         d->rel_hdr.sh_info = d->this_idx;
+       }
+
+      switch (d->this_hdr.sh_type)
        {
-         /* @@ Do something with sh_type?  */
+       case SHT_REL:
+       case SHT_RELA:
+         /* A reloc section which we are treating as a normal BFD
+            section.  sh_link is the section index of the symbol
+            table.  sh_info is the section index of the section to
+            which the relocation entries apply.  We assume that an
+            allocated reloc section uses the dynamic symbol table.
+            FIXME: How can we be sure?  */
+         s = bfd_get_section_by_name (abfd, ".dynsym");
+         if (s != NULL)
+           d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+
+         /* We look up the section the relocs apply to by name.  */
+         name = sec->name;
+         if (d->this_hdr.sh_type == SHT_REL)
+           name += 4;
+         else
+           name += 5;
+         s = bfd_get_section_by_name (abfd, name);
+         if (s != NULL)
+           d->this_hdr.sh_info = elf_section_data (s)->this_idx;
+         break;
+
+       case SHT_STRTAB:
+         /* We assume that a section named .stab*str is a stabs
+            string section.  We look for a section with the same name
+            but without the trailing ``str'', and set its sh_link
+            field to point to this section.  */
+         if (strncmp (sec->name, ".stab", sizeof ".stab" - 1) == 0
+             && strcmp (sec->name + strlen (sec->name) - 3, "str") == 0)
+           {
+             size_t len;
+             char *alc;
+
+             len = strlen (sec->name);
+             alc = (char *) malloc (len - 2);
+             if (alc == NULL)
+               {
+                 bfd_set_error (bfd_error_no_memory);
+                 return false;
+               }
+             strncpy (alc, sec->name, len - 3);
+             alc[len - 3] = '\0';
+             s = bfd_get_section_by_name (abfd, alc);
+             free (alc);
+             if (s != NULL)
+               {
+                 elf_section_data (s)->this_hdr.sh_link = d->this_idx;
+
+                 /* This is a .stab section.  */
+                 elf_section_data (s)->this_hdr.sh_entsize =
+                   4 + 2 * (ARCH_SIZE / 8);
+               }
+           }
+         break;
+
+       case SHT_DYNAMIC:
+       case SHT_DYNSYM:
+         /* sh_link is the section header index of the string table
+            used for the dynamic entries or symbol table.  */
+         s = bfd_get_section_by_name (abfd, ".dynstr");
+         if (s != NULL)
+           d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+         break;
+
+       case SHT_HASH:
+         /* sh_link is the section header index of the symbol table
+            this hash table is for.  */
+         s = bfd_get_section_by_name (abfd, ".dynsym");
+         if (s != NULL)
+           d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+         break;
        }
     }
-  if (!(asect->flags & SEC_READONLY))
-    this_hdr->sh_flags |= SHF_WRITE;
-  if (asect->flags & SEC_CODE)
-    this_hdr->sh_flags |= SHF_EXECINSTR;
+
+  return true;
 }
 
 /* Map symbol from it's internal number to the external number, moving
@@ -1540,10 +1620,6 @@ elf_compute_section_file_positions (abfd, link_info)
   if (!assign_section_numbers (abfd))
     return false;
 
-  bfd_map_over_sections (abfd, elf_make_sections, 0);
-
-  bfd_map_over_sections (abfd, fix_up_strtabs, 0);     /* .stab/.stabstr &c */
-
   /* The backend linker builds symbol table information itself.  */
   if (link_info == NULL)
     {
@@ -1574,89 +1650,6 @@ elf_compute_section_file_positions (abfd, link_info)
 }
 
 
-/* Assign all ELF section numbers.  The dummy first section is handled here
-   too.  The link/info pointers for the standard section types are filled
-   in here too, while we're at it.  (Link pointers for .stab sections are
-   not filled in here.)  */
-static boolean
-assign_section_numbers (abfd)
-     bfd *abfd;
-{
-  struct elf_obj_tdata *t = elf_tdata (abfd);
-  asection *sec;
-  int section_number = 1;
-  int i;
-  Elf_Internal_Shdr **i_shdrp;
-
-  t->shstrtab_hdr.sh_size = elf_shstrtab (abfd)->length;
-  t->shstrtab_hdr.contents = (void *) elf_shstrtab (abfd)->tab;
-
-  t->shstrtab_section = section_number++;
-  elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section;
-  if (abfd->symcount)
-    {
-      t->symtab_section = section_number++;
-      t->strtab_section = section_number++;
-      t->symtab_hdr.sh_link = t->strtab_section;
-    }
-  for (sec = abfd->sections; sec; sec = sec->next)
-    {
-      struct bfd_elf_section_data *d = elf_section_data (sec);
-      d->this_idx = section_number++;
-      if (sec->flags & SEC_RELOC)
-       {
-         d->rel_idx = section_number++;
-         d->rel_hdr.sh_link = t->symtab_section;
-         d->rel_hdr.sh_info = d->this_idx;
-       }
-      else
-       d->rel_idx = 0;
-      /* No handling for per-section string tables currently.  */
-    }
-  elf_elfheader (abfd)->e_shnum = section_number;
-
-  /* Set up the list of section header pointers, in agreement with the
-     indices.  */
-  i_shdrp = ((Elf_Internal_Shdr **)
-            bfd_alloc (abfd, section_number * sizeof (Elf_Internal_Shdr *)));
-  if (i_shdrp == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
-  i_shdrp[0] = ((Elf_Internal_Shdr *)
-               bfd_alloc (abfd, sizeof (Elf_Internal_Shdr)));
-  if (i_shdrp[0] == NULL)
-    {
-      bfd_release (abfd, i_shdrp);
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
-  elf_elfsections (abfd) = i_shdrp;
-  for (i = 1; i < section_number; i++)
-    i_shdrp[i] = NULL;
-  memset (i_shdrp[0], 0, sizeof (Elf_Internal_Shdr));
-
-  i_shdrp[t->shstrtab_section] = &t->shstrtab_hdr;
-  if (abfd->symcount)
-    {
-      i_shdrp[t->symtab_section] = &t->symtab_hdr;
-      i_shdrp[t->strtab_section] = &t->strtab_hdr;
-    }
-  for (sec = abfd->sections; sec; sec = sec->next)
-    {
-      struct bfd_elf_section_data *d = elf_section_data (sec);
-      i_shdrp[d->this_idx] = &d->this_hdr;
-      if (d->rel_idx)
-       i_shdrp[d->rel_idx] = &d->rel_hdr;
-    }
-  /* Make sure we got everything.... */
-  for (i = 0; i < section_number; i++)
-    if (i_shdrp[i] == NULL)
-      abort ();
-  return true;
-}
-
 /* Align to the maximum file alignment that could be required for any
    ELF data structure.  */
 
@@ -2246,13 +2239,8 @@ swap_out_syms (abfd)
     symtab_hdr->sh_entsize = sizeof (Elf_External_Sym);
     symtab_hdr->sh_size = symtab_hdr->sh_entsize * (symcount + 1);
     symtab_hdr->sh_info = elf_num_locals (abfd) + 1;
+    symtab_hdr->sh_addralign = FILE_ALIGN;
 
-    /* FIXME: Systems I've checked use 4 byte alignment for .symtab,
-       but it is possible that there are systems which use a different
-       alignment.  */
-    symtab_hdr->sh_addralign = 4;
-
-    /* see assert in elf_fake_sections that supports this: */
     symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
     symstrtab_hdr->sh_type = SHT_STRTAB;
 
@@ -2473,15 +2461,6 @@ NAME(bfd_elf,write_object_contents) (abfd)
   Elf_Internal_Shdr **i_shdrp;
   unsigned int count;
 
-  /* We don't know how to write dynamic objects.  Specifically, we
-     don't know how to construct the program header.  */
-  if ((abfd->flags & DYNAMIC) != 0)
-    {
-      fprintf (stderr, "Writing ELF dynamic objects is not supported\n");
-      bfd_set_error (bfd_error_wrong_format);
-      return false;
-    }
-
   if (! abfd->output_has_begun
       && ! elf_compute_section_file_positions (abfd,
                                               (struct bfd_link_info *) NULL))
@@ -2591,6 +2570,7 @@ elf_section_from_bfd_section (abfd, asect)
        case SHT_NOTE:
        case SHT_HASH:
        case SHT_DYNAMIC:
+       case SHT_DYNSYM:
          if (hdr->rawdata)
            {
              if (((struct sec *) (hdr->rawdata)) == asect)
@@ -2598,19 +2578,22 @@ elf_section_from_bfd_section (abfd, asect)
            }
          break;
 
+       case SHT_REL:
+       case SHT_RELA:
+         /* We sometimes map a reloc section to a BFD section.  */
+         if (((hdr->sh_flags & SHF_ALLOC) != 0
+              || hdr->sh_link != elf_onesymtab (abfd))
+             && (asection *) hdr->rawdata == asect)
+           return index;
+         break;
+
        case SHT_STRTAB:
-         /* fix_up_strtabs will generate STRTAB sections with names
-            of .stab*str.  */
-         if (!strncmp (asect->name, ".stab", 5)
-             && !strcmp ("str", asect->name + strlen (asect->name) - 3))
-           {
-             if (hdr->rawdata)
-               {
-                 if (((struct sec *) (hdr->rawdata)) == asect)
-                   return index;
-               }
-             break;
-           }
+         /* We map most string tables to BFD sections.  */
+         if (index != elf_elfheader (abfd)->e_shstrndx
+             && index != elf_onesymtab (abfd)
+             && (asection *) hdr->rawdata == asect)
+           return index;
+
          /* FALL THROUGH */
        default:
          {
@@ -5524,10 +5507,6 @@ elf_bfd_final_link (abfd, info)
 
       for (o = dynobj->sections; o != NULL; o = o->next)
        {
-         Elf_Internal_Shdr *hdr;
-         asection *s;
-         const char *name;
-
          if ((o->flags & SEC_HAS_CONTENTS) == 0)
            continue;
          BFD_ASSERT ((o->flags & SEC_IN_MEMORY) != 0);
@@ -5535,48 +5514,6 @@ elf_bfd_final_link (abfd, info)
                                          o->contents, o->output_offset,
                                          o->_raw_size))
            goto error_return;
-
-         hdr = &elf_section_data (o->output_section)->this_hdr;
-         switch (hdr->sh_type)
-           {
-           case SHT_DYNAMIC:
-             s = bfd_get_section_by_name (abfd, ".dynstr");
-             hdr->sh_link = elf_section_data (s)->this_idx;
-             hdr->sh_entsize = sizeof (Elf_External_Dyn);
-             break;
-
-           case SHT_HASH:
-             s = finfo.dynsym_sec->output_section;
-             hdr->sh_link = elf_section_data (s)->this_idx;
-             hdr->sh_entsize = ARCH_SIZE / 8;
-             break;
-
-           case SHT_DYNSYM:
-             s = bfd_get_section_by_name (abfd, ".dynstr");
-             hdr->sh_link = elf_section_data (s)->this_idx;
-             hdr->sh_entsize = sizeof (Elf_External_Sym);
-             break;
-
-           case SHT_REL:
-           case SHT_RELA:
-             name = bfd_get_section_name (abfd, o->output_section);
-             s = finfo.dynsym_sec->output_section;
-             hdr->sh_link = elf_section_data (s)->this_idx;
-             if (hdr->sh_type == SHT_REL)
-               {
-                 name += 4;
-                 hdr->sh_entsize = sizeof (Elf_External_Rel);
-               }
-             else
-               {
-                 name += 5;
-                 hdr->sh_entsize = sizeof (Elf_External_Rela);
-               }
-             s = bfd_get_section_by_name (abfd, name);
-             if (s != NULL)
-               hdr->sh_info = elf_section_data (s)->this_idx;
-             break;
-           }
        }
     }