* coffcode.h (coff_slurp_symbol_table): If COFF_WITH_PE or
[deliverable/binutils-gdb.git] / bfd / cofflink.c
index 999a81e1bbb87043e5ca496802701ab2fc8f4f43..c721bdf9de1fa75588eea9f1ee5e0baf0bedd939 100644 (file)
@@ -1,5 +1,5 @@
 /* COFF specific linker code.
 /* COFF specific linker code.
-   Copyright 1994, 1995 Free Software Foundation, Inc.
+   Copyright 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
    Written by Ian Lance Taylor, Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -34,6 +34,10 @@ static boolean coff_link_check_archive_element
 static boolean coff_link_check_ar_symbols
   PARAMS ((bfd *, struct bfd_link_info *, boolean *));
 static boolean coff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *));
 static boolean coff_link_check_ar_symbols
   PARAMS ((bfd *, struct bfd_link_info *, boolean *));
 static boolean coff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *));
+static char *dores_com PARAMS ((char *, bfd *, int));
+static char *get_name PARAMS ((char *, char **));
+static int process_embedded_commands
+  PARAMS ((bfd *, struct bfd_link_info *, bfd *));
 
 /* Create an entry in a COFF linker hash table.  */
 
 
 /* Create an entry in a COFF linker hash table.  */
 
@@ -81,6 +85,7 @@ _bfd_coff_link_hash_table_init (table, abfd, newfunc)
                                                struct bfd_hash_table *,
                                                const char *));
 {
                                                struct bfd_hash_table *,
                                                const char *));
 {
+  table->stab_info = NULL;
   return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
 }
 
   return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
 }
 
@@ -282,6 +287,7 @@ coff_link_add_symbols (abfd, info)
      struct bfd_link_info *info;
 {
   boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *));
      struct bfd_link_info *info;
 {
   boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *));
+  boolean keep_syms;
   boolean default_copy;
   bfd_size_type symcount;
   struct coff_link_hash_entry **sym_hash;
   boolean default_copy;
   bfd_size_type symcount;
   struct coff_link_hash_entry **sym_hash;
@@ -289,6 +295,11 @@ coff_link_add_symbols (abfd, info)
   bfd_byte *esym;
   bfd_byte *esym_end;
 
   bfd_byte *esym;
   bfd_byte *esym_end;
 
+  /* Keep the symbols during this function, in case the linker needs
+     to read the generic symbols in order to report an error message.  */
+  keep_syms = obj_coff_keep_syms (abfd);
+  obj_coff_keep_syms (abfd) = true;
+
   sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global;
 
   if (info->keep_memory)
   sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global;
 
   if (info->keep_memory)
@@ -305,7 +316,7 @@ coff_link_add_symbols (abfd, info)
                         ((size_t) symcount
                          * sizeof (struct coff_link_hash_entry *))));
   if (sym_hash == NULL && symcount != 0)
                         ((size_t) symcount
                          * sizeof (struct coff_link_hash_entry *))));
   if (sym_hash == NULL && symcount != 0)
-    return false;
+    goto error_return;
   obj_coff_sym_hashes (abfd) = sym_hash;
   memset (sym_hash, 0,
          (size_t) symcount * sizeof (struct coff_link_hash_entry *));
   obj_coff_sym_hashes (abfd) = sym_hash;
   memset (sym_hash, 0,
          (size_t) symcount * sizeof (struct coff_link_hash_entry *));
@@ -334,7 +345,7 @@ coff_link_add_symbols (abfd, info)
 
          name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
          if (name == NULL)
 
          name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
          if (name == NULL)
-           return false;
+           goto error_return;
 
          /* We must copy the name into memory if we got it from the
              syment itself, rather than the string table.  */
 
          /* We must copy the name into memory if we got it from the
              syment itself, rather than the string table.  */
@@ -365,11 +376,18 @@ coff_link_add_symbols (abfd, info)
              value -= section->vma;
            }
 
              value -= section->vma;
            }
 
-         if (! (_bfd_generic_link_add_one_symbol
+         if (! (bfd_coff_link_add_one_symbol
                 (info, abfd, name, flags, section, value,
                  (const char *) NULL, copy, false,
                  (struct bfd_link_hash_entry **) sym_hash)))
                 (info, abfd, name, flags, section, value,
                  (const char *) NULL, copy, false,
                  (struct bfd_link_hash_entry **) sym_hash)))
-           return false;
+           goto error_return;
+
+         if (section == bfd_com_section_ptr
+             && (*sym_hash)->root.type == bfd_link_hash_common
+             && ((*sym_hash)->root.u.c.p->alignment_power
+                 > bfd_coff_default_section_alignment_power (abfd)))
+           (*sym_hash)->root.u.c.p->alignment_power
+             = bfd_coff_default_section_alignment_power (abfd);
 
          if (info->hash->creator->flavour == bfd_get_flavour (abfd))
            {
 
          if (info->hash->creator->flavour == bfd_get_flavour (abfd))
            {
@@ -380,8 +398,16 @@ coff_link_add_symbols (abfd, info)
                      && (*sym_hash)->root.type != bfd_link_hash_defined))
                {
                  (*sym_hash)->class = sym.n_sclass;
                      && (*sym_hash)->root.type != bfd_link_hash_defined))
                {
                  (*sym_hash)->class = sym.n_sclass;
-                 (*sym_hash)->type = sym.n_type;
-                 (*sym_hash)->numaux = sym.n_numaux;
+                 if (sym.n_type != T_NULL)
+                   {
+                     if ((*sym_hash)->type != T_NULL
+                         && (*sym_hash)->type != sym.n_type)
+                       (*_bfd_error_handler)
+                         ("Warning: type of symbol `%s' changed from %d to %d in %s",
+                          name, (*sym_hash)->type, sym.n_type,
+                          bfd_get_filename (abfd));
+                     (*sym_hash)->type = sym.n_type;
+                   }
                  (*sym_hash)->auxbfd = abfd;
                  if (sym.n_numaux != 0)
                    {
                  (*sym_hash)->auxbfd = abfd;
                  if (sym.n_numaux != 0)
                    {
@@ -390,12 +416,13 @@ coff_link_add_symbols (abfd, info)
                      bfd_byte *eaux;
                      union internal_auxent *iaux;
 
                      bfd_byte *eaux;
                      union internal_auxent *iaux;
 
+                     (*sym_hash)->numaux = sym.n_numaux;
                      alloc = ((union internal_auxent *)
                               bfd_hash_allocate (&info->hash->table,
                                                  (sym.n_numaux
                                                   * sizeof (*alloc))));
                      if (alloc == NULL)
                      alloc = ((union internal_auxent *)
                               bfd_hash_allocate (&info->hash->table,
                                                  (sym.n_numaux
                                                   * sizeof (*alloc))));
                      if (alloc == NULL)
-                       return false;
+                       goto error_return;
                      for (i = 0, eaux = esym + symesz, iaux = alloc;
                           i < sym.n_numaux;
                           i++, eaux += symesz, iaux++)
                      for (i = 0, eaux = esym + symesz, iaux = alloc;
                           i < sym.n_numaux;
                           i++, eaux += symesz, iaux++)
@@ -412,7 +439,53 @@ coff_link_add_symbols (abfd, info)
       sym_hash += sym.n_numaux + 1;
     }
 
       sym_hash += sym.n_numaux + 1;
     }
 
+  /* If this is a non-traditional, non-relocateable link, try to
+     optimize the handling of any .stab/.stabstr sections.  */
+  if (! info->relocateable
+      && ! info->traditional_format
+      && info->hash->creator->flavour == bfd_get_flavour (abfd)
+      && (info->strip != strip_all && info->strip != strip_debugger))
+    {
+      asection *stab, *stabstr;
+
+      stab = bfd_get_section_by_name (abfd, ".stab");
+      if (stab != NULL)
+       {
+         stabstr = bfd_get_section_by_name (abfd, ".stabstr");
+
+         if (stabstr != NULL)
+           {
+             struct coff_link_hash_table *table;
+             struct coff_section_tdata *secdata;
+
+             secdata = coff_section_data (abfd, stab);
+             if (secdata == NULL)
+               {
+                 stab->used_by_bfd =
+                   (PTR) bfd_zalloc (abfd,
+                                     sizeof (struct coff_section_tdata));
+                 if (stab->used_by_bfd == NULL)
+                   goto error_return;
+                 secdata = coff_section_data (abfd, stab);
+               }
+
+             table = coff_hash_table (info);
+
+             if (! _bfd_link_section_stabs (abfd, &table->stab_info,
+                                            stab, stabstr,
+                                            &secdata->stab_info))
+               goto error_return;
+           }
+       }
+    }
+
+  obj_coff_keep_syms (abfd) = keep_syms;
+
   return true;
   return true;
+
+ error_return:
+  obj_coff_keep_syms (abfd) = keep_syms;
+  return false;
 }
 \f
 /* Do the final link step.  */
 }
 \f
 /* Do the final link step.  */
@@ -425,6 +498,7 @@ _bfd_coff_final_link (abfd, info)
   bfd_size_type symesz;
   struct coff_final_link_info finfo;
   boolean debug_merge_allocated;
   bfd_size_type symesz;
   struct coff_final_link_info finfo;
   boolean debug_merge_allocated;
+  boolean long_section_names;
   asection *o;
   struct bfd_link_order *p;
   size_t max_sym_count;
   asection *o;
   struct bfd_link_order *p;
   size_t max_sym_count;
@@ -447,6 +521,7 @@ _bfd_coff_final_link (abfd, info)
   finfo.strtab = NULL;
   finfo.section_info = NULL;
   finfo.last_file_index = -1;
   finfo.strtab = NULL;
   finfo.section_info = NULL;
   finfo.last_file_index = -1;
+  finfo.last_bf_index = -1;
   finfo.internal_syms = NULL;
   finfo.sec_ptrs = NULL;
   finfo.sym_indices = NULL;
   finfo.internal_syms = NULL;
   finfo.sec_ptrs = NULL;
   finfo.sym_indices = NULL;
@@ -469,7 +544,10 @@ _bfd_coff_final_link (abfd, info)
 
   /* Compute the file positions for all the sections.  */
   if (! abfd->output_has_begun)
 
   /* Compute the file positions for all the sections.  */
   if (! abfd->output_has_begun)
-    bfd_coff_compute_section_file_positions (abfd);
+    {
+      if (! bfd_coff_compute_section_file_positions (abfd))
+       goto error_return;
+    }
 
   /* Count the line numbers and relocation entries required for the
      output file.  Set the file positions for the relocs.  */
 
   /* Count the line numbers and relocation entries required for the
      output file.  Set the file positions for the relocs.  */
@@ -479,19 +557,25 @@ _bfd_coff_final_link (abfd, info)
   max_lineno_count = 0;
   max_reloc_count = 0;
 
   max_lineno_count = 0;
   max_reloc_count = 0;
 
+  long_section_names = false;
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       o->reloc_count = 0;
       o->lineno_count = 0;
       for (p = o->link_order_head; p != NULL; p = p->next)
        {
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       o->reloc_count = 0;
       o->lineno_count = 0;
       for (p = o->link_order_head; p != NULL; p = p->next)
        {
-
          if (p->type == bfd_indirect_link_order)
            {
              asection *sec;
 
              sec = p->u.indirect.section;
 
          if (p->type == bfd_indirect_link_order)
            {
              asection *sec;
 
              sec = p->u.indirect.section;
 
+             /* Mark all sections which are to be included in the
+                link.  This will normally be every section.  We need
+                to do this so that we can identify any sections which
+                the linker has decided to not include.  */
+             sec->linker_mark = true;
+
              if (info->strip == strip_none
                  || info->strip == strip_some)
                o->lineno_count += sec->lineno_count;
              if (info->strip == strip_none
                  || info->strip == strip_some)
                o->lineno_count += sec->lineno_count;
@@ -519,6 +603,20 @@ _bfd_coff_final_link (abfd, info)
          o->rel_filepos = rel_filepos;
          rel_filepos += o->reloc_count * relsz;
        }
          o->rel_filepos = rel_filepos;
          rel_filepos += o->reloc_count * relsz;
        }
+
+      if (bfd_coff_long_section_names (abfd)
+         && strlen (o->name) > SCNNMLEN)
+       {
+         /* This section has a long name which must go in the string
+             table.  This must correspond to the code in
+             coff_write_object_contents which puts the string index
+             into the s_name field of the section header.  That is why
+             we pass hash as false.  */
+         if (_bfd_stringtab_add (finfo.strtab, o->name, false, false)
+             == (bfd_size_type) -1)
+           goto error_return;
+         long_section_names = true;
+       }
     }
 
   /* If doing a relocateable link, allocate space for the pointers we
     }
 
   /* If doing a relocateable link, allocate space for the pointers we
@@ -754,7 +852,7 @@ _bfd_coff_final_link (abfd, info)
       finfo.outsyms = NULL;
     }
 
       finfo.outsyms = NULL;
     }
 
-  if (info->relocateable)
+  if (info->relocateable && max_output_reloc_count > 0)
     {
       /* Now that we have written out all the global symbols, we know
         the symbol indices to use for relocs against them, and we can
     {
       /* Now that we have written out all the global symbols, we know
         the symbol indices to use for relocs against them, and we can
@@ -814,8 +912,15 @@ _bfd_coff_final_link (abfd, info)
       finfo.section_info = NULL;
     }
 
       finfo.section_info = NULL;
     }
 
+  /* If we have optimized stabs strings, output them.  */
+  if (coff_hash_table (info)->stab_info != NULL)
+    {
+      if (! _bfd_write_stab_strings (abfd, &coff_hash_table (info)->stab_info))
+       return false;
+    }
+
   /* Write out the string table.  */
   /* Write out the string table.  */
-  if (obj_raw_syment_count (abfd) != 0)
+  if (obj_raw_syment_count (abfd) != 0 || long_section_names)
     {
       if (bfd_seek (abfd,
                    (obj_sym_filepos (abfd)
     {
       if (bfd_seek (abfd,
                    (obj_sym_filepos (abfd)
@@ -1012,6 +1117,60 @@ process_embedded_commands (output_bfd, info,  abfd)
   return 1;
 }
 
   return 1;
 }
 
+/* Place a marker against all symbols which are used by relocations.
+   This marker can be picked up by the 'do we skip this symbol ?'
+   loop in _bfd_coff_link_input_bfd() and used to prevent skipping
+   that symbol. 
+   */
+
+static void
+mark_relocs (finfo, input_bfd)
+     struct coff_final_link_info *     finfo;
+     bfd *                             input_bfd;
+{
+  asection * a;
+
+  if ((bfd_get_file_flags (input_bfd) & HAS_SYMS) == 0)
+    return;
+  
+  for (a = input_bfd->sections; a != (asection *) NULL; a = a->next)
+    {
+      struct internal_reloc *  internal_relocs;
+      struct internal_reloc *  irel;
+      struct internal_reloc *  irelend;
+
+      
+      if ((a->flags & SEC_RELOC) == 0 || a->reloc_count  < 1)
+       continue;
+
+      /* Read in the relocs.  */
+      internal_relocs = _bfd_coff_read_internal_relocs
+       (input_bfd, a, false,
+        finfo->external_relocs,
+        finfo->info->relocateable,
+        (finfo->info->relocateable
+         ? (finfo->section_info[ a->output_section->target_index ].relocs + a->output_section->reloc_count)
+         : finfo->internal_relocs)
+       );
+      
+      if (internal_relocs == NULL)
+       continue;
+
+      irel     = internal_relocs;
+      irelend  = irel + a->reloc_count;
+
+      /* Place a mark in the sym_indices array (whose entries have
+        been initialised to 0) for all of the symbols that are used
+        in the relocation table.  This will then be picked up in the
+        skip/don't pass */
+      
+      for (; irel < irelend; irel++)
+       {
+         finfo->sym_indices[ irel->r_symndx ] = -1;
+       }
+    }
+}
+
 /* Link an input file into the linker output file.  This function
    handles all the sections and relocations of the input file at once.  */
 
 /* Link an input file into the linker output file.  This function
    handles all the sections and relocations of the input file at once.  */
 
@@ -1079,17 +1238,31 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
   output_index = syment_base;
   outsym = finfo->outsyms;
 
   output_index = syment_base;
   outsym = finfo->outsyms;
 
-  if (coff_data(output_bfd)->pe)
-      {
-       if (!process_embedded_commands (output_bfd, finfo->info, input_bfd))
-         return false;
-      }
+  if (coff_data (output_bfd)->pe)
+    {
+      if (! process_embedded_commands (output_bfd, finfo->info, input_bfd))
+       return false;
+    }
+
+  /* If we are going to perform relocations and also strip/discard some symbols
+     then we must make sure that we do not strip/discard those symbols that are
+     going to be involved in the relocations */
+  if ((   finfo->info->strip   != strip_none
+       || finfo->info->discard != discard_none)
+      && finfo->info->relocateable)
+    {
+      /* mark the symbol array as 'not-used' */
+      memset (indexp, 0, obj_raw_syment_count (input_bfd) * sizeof * indexp); 
+       
+      mark_relocs (finfo, input_bfd);
+    }
 
   while (esym < esym_end)
     {
       struct internal_syment isym;
       boolean skip;
       boolean global;
 
   while (esym < esym_end)
     {
       struct internal_syment isym;
       boolean skip;
       boolean global;
+      boolean dont_skip_symbol;
       int add;
 
       bfd_coff_swap_sym_in (input_bfd, (PTR) esym, (PTR) isymp);
       int add;
 
       bfd_coff_swap_sym_in (input_bfd, (PTR) esym, (PTR) isymp);
@@ -1110,6 +1283,14 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
            *secpp = bfd_com_section_ptr;
        }
 
            *secpp = bfd_com_section_ptr;
        }
 
+      /* Extract the flag indicating if this symbol is used by a relocation */
+      if ((   finfo->info->strip   != strip_none
+          || finfo->info->discard != discard_none)
+         && finfo->info->relocateable)
+       dont_skip_symbol = *indexp;
+      else
+       dont_skip_symbol = false;
+      
       *indexp = -1;
 
       skip = false;
       *indexp = -1;
 
       skip = false;
@@ -1117,7 +1298,7 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
       add = 1 + isym.n_numaux;
 
       /* If we are stripping all symbols, we want to skip this one.  */
       add = 1 + isym.n_numaux;
 
       /* If we are stripping all symbols, we want to skip this one.  */
-      if (finfo->info->strip == strip_all)
+      if (finfo->info->strip == strip_all && ! dont_skip_symbol)
        skip = true;
 
       if (! skip)
        skip = true;
 
       if (! skip)
@@ -1137,7 +1318,7 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
            {
              /* This is a local symbol.  Skip it if we are discarding
                  local symbols.  */
            {
              /* This is a local symbol.  Skip it if we are discarding
                  local symbols.  */
-             if (finfo->info->discard == discard_all)
+             if (finfo->info->discard == discard_all && ! dont_skip_symbol)
                skip = true;
            }
        }
                skip = true;
            }
        }
@@ -1146,6 +1327,7 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
          symbol, then skip it.  */
       if (! skip
          && finfo->info->strip == strip_debugger
          symbol, then skip it.  */
       if (! skip
          && finfo->info->strip == strip_debugger
+         && ! dont_skip_symbol
          && isym.n_scnum == N_DEBUG)
        skip = true;
 
          && isym.n_scnum == N_DEBUG)
        skip = true;
 
@@ -1162,13 +1344,13 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
          if (name == NULL)
            return false;
 
          if (name == NULL)
            return false;
 
-         if ((finfo->info->strip == strip_some
-              && (bfd_hash_lookup (finfo->info->keep_hash, name, false,
+         if (! dont_skip_symbol
+             && ((finfo->info->strip == strip_some
+                  && (bfd_hash_lookup (finfo->info->keep_hash, name, false,
                                    false) == NULL))
                                    false) == NULL))
-             || (! global
-                 && finfo->info->discard == discard_l
-                 && strncmp (name, finfo->info->lprefix,
-                             finfo->info->lprefix_len) == 0))
+                  || (! global
+                      && finfo->info->discard == discard_l
+                      && bfd_is_local_label_name (input_bfd, name))))
            skip = true;
        }
 
            skip = true;
        }
 
@@ -1189,7 +1371,6 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
          struct coff_debug_merge_element **epp;
          bfd_byte *esl, *eslend;
          struct internal_syment *islp;
          struct coff_debug_merge_element **epp;
          bfd_byte *esl, *eslend;
          struct internal_syment *islp;
-         struct coff_debug_merge_type *mtl;
 
          name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
          if (name == NULL)
 
          name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
          if (name == NULL)
@@ -1197,9 +1378,9 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
 
          /* Ignore fake names invented by compiler; treat them all as
              the same name.  */
 
          /* Ignore fake names invented by compiler; treat them all as
              the same name.  */
-         if (*name == '~' || *name == '.'
+         if (*name == '~' || *name == '.' || *name == '$'
              || (*name == bfd_get_symbol_leading_char (input_bfd)
              || (*name == bfd_get_symbol_leading_char (input_bfd)
-                 && (name[1] == '~' || name[1] == '.')))
+                 && (name[1] == '~' || name[1] == '.' || name[1] == '$')))
            name = "";
 
          mh = coff_debug_merge_hash_lookup (&finfo->debug_merge, name,
            name = "";
 
          mh = coff_debug_merge_hash_lookup (&finfo->debug_merge, name,
@@ -1293,42 +1474,50 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
            }
 
          /* See if we already have a definition which matches this
            }
 
          /* See if we already have a definition which matches this
-             type.  */
-         for (mtl = mh->types; mtl != NULL; mtl = mtl->next)
+             type.  We always output the type if it has no elements,
+             for simplicity.  */
+         if (mt->elements == NULL)
+           bfd_release (input_bfd, (PTR) mt);
+         else
            {
            {
-             struct coff_debug_merge_element *me, *mel;
+             struct coff_debug_merge_type *mtl;
 
 
-             if (mtl->class != mt->class)
-               continue;
-
-             for (me = mt->elements, mel = mtl->elements;
-                  me != NULL && mel != NULL;
-                  me = me->next, mel = mel->next)
+             for (mtl = mh->types; mtl != NULL; mtl = mtl->next)
                {
                {
-                 if (strcmp (me->name, mel->name) != 0
-                     || me->type != mel->type
-                     || me->tagndx != mel->tagndx)
+                 struct coff_debug_merge_element *me, *mel;
+
+                 if (mtl->class != mt->class)
+                   continue;
+
+                 for (me = mt->elements, mel = mtl->elements;
+                      me != NULL && mel != NULL;
+                      me = me->next, mel = mel->next)
+                   {
+                     if (strcmp (me->name, mel->name) != 0
+                         || me->type != mel->type
+                         || me->tagndx != mel->tagndx)
+                       break;
+                   }
+
+                 if (me == NULL && mel == NULL)
                    break;
                }
 
                    break;
                }
 
-             if (me == NULL && mel == NULL)
-               break;
-           }
-
-         if (mtl == NULL || (bfd_size_type) mtl->indx >= syment_base)
-           {
-             /* This is the first definition of this type.  */
-             mt->indx = output_index;
-             mt->next = mh->types;
-             mh->types = mt;
-           }
-         else
-           {
-             /* This is a redefinition which can be merged.  */
-             bfd_release (input_bfd, (PTR) mt);
-             *indexp = mtl->indx;
-             add = (eslend - esym) / isymesz;
-             skip = true;
+             if (mtl == NULL || (bfd_size_type) mtl->indx >= syment_base)
+               {
+                 /* This is the first definition of this type.  */
+                 mt->indx = output_index;
+                 mt->next = mh->types;
+                 mh->types = mt;
+               }
+             else
+               {
+                 /* This is a redefinition which can be merged.  */
+                 bfd_release (input_bfd, (PTR) mt);
+                 *indexp = mtl->indx;
+                 add = (eslend - esym) / isymesz;
+                 skip = true;
+               }
            }
        }
 
            }
        }
 
@@ -1361,9 +1550,10 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
          if (isym.n_scnum > 0)
            {
              isym.n_scnum = (*secpp)->output_section->target_index;
          if (isym.n_scnum > 0)
            {
              isym.n_scnum = (*secpp)->output_section->target_index;
-             isym.n_value += ((*secpp)->output_section->vma
-                              + (*secpp)->output_offset
-                              - (*secpp)->vma);
+             isym.n_value += (*secpp)->output_offset;
+             if (! obj_pe (finfo->output_bfd))
+               isym.n_value += ((*secpp)->output_section->vma
+                                - (*secpp)->vma);
            }
 
          /* The value of a C_FILE symbol is the symbol index of the
            }
 
          /* The value of a C_FILE symbol is the symbol index of the
@@ -1428,7 +1618,13 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
              indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd))
                      / isymesz);
              h = obj_coff_sym_hashes (input_bfd)[indx];
              indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd))
                      / isymesz);
              h = obj_coff_sym_hashes (input_bfd)[indx];
-             BFD_ASSERT (h != NULL);
+             if (h == NULL)
+               {
+                 /* This can happen if there were errors earlier in
+                     the link.  */
+                 bfd_set_error (bfd_error_bad_value);
+                 return false;
+               }
              h->indx = output_index;
            }
 
              h->indx = output_index;
            }
 
@@ -1477,7 +1673,12 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
          if (*indexp < 0)
            {
              h = *sym_hash;
          if (*indexp < 0)
            {
              h = *sym_hash;
-             BFD_ASSERT (h->numaux == isymp->n_numaux);
+
+             /* The m68k-motorola-sysv assembler will sometimes
+                 generate two symbols with the same name, but only one
+                 will have aux entries.  */
+             BFD_ASSERT (isymp->n_numaux == 0
+                         || h->numaux == isymp->n_numaux);
            }
 
          esym += isymesz;
            }
 
          esym += isymesz;
@@ -1534,7 +1735,8 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
 
                  if (ISFCN (isymp->n_type)
                      || ISTAG (isymp->n_sclass)
 
                  if (ISFCN (isymp->n_type)
                      || ISTAG (isymp->n_sclass)
-                     || isymp->n_sclass == C_BLOCK)
+                     || isymp->n_sclass == C_BLOCK
+                     || isymp->n_sclass == C_FCN)
                    {
                      indx = auxp->x_sym.x_fcnary.x_fcn.x_endndx.l;
                      if (indx > 0
                    {
                      indx = auxp->x_sym.x_fcnary.x_fcn.x_endndx.l;
                      if (indx > 0
@@ -1544,7 +1746,9 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
                              the index of the next symbol we are going
                              to include.  I don't know if this is
                              entirely right.  */
                              the index of the next symbol we are going
                              to include.  I don't know if this is
                              entirely right.  */
-                         while (finfo->sym_indices[indx] < 0
+                         while ((finfo->sym_indices[indx] < 0
+                                 || ((bfd_size_type) finfo->sym_indices[indx]
+                                     < syment_base))
                                 && indx < obj_raw_syment_count (input_bfd))
                            ++indx;
                          if (indx >= obj_raw_syment_count (input_bfd))
                                 && indx < obj_raw_syment_count (input_bfd))
                            ++indx;
                          if (indx >= obj_raw_syment_count (input_bfd))
@@ -1566,6 +1770,81 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
                      else
                        auxp->x_sym.x_tagndx.l = symindx;
                    }
                      else
                        auxp->x_sym.x_tagndx.l = symindx;
                    }
+
+                 /* The .bf symbols are supposed to be linked through
+                    the endndx field.  We need to carry this list
+                    across object files.  */
+                 if (i == 0
+                     && h == NULL
+                     && isymp->n_sclass == C_FCN
+                     && (isymp->_n._n_n._n_zeroes != 0
+                         || isymp->_n._n_n._n_offset == 0)
+                     && isymp->_n._n_name[0] == '.'
+                     && isymp->_n._n_name[1] == 'b'
+                     && isymp->_n._n_name[2] == 'f'
+                     && isymp->_n._n_name[3] == '\0')
+                   {
+                     if (finfo->last_bf_index != -1)
+                       {
+                         finfo->last_bf.x_sym.x_fcnary.x_fcn.x_endndx.l =
+                           *indexp;
+
+                         if ((bfd_size_type) finfo->last_bf_index
+                             >= syment_base)
+                           {
+                             PTR auxout;
+
+                             /* The last .bf symbol is in this input
+                                file.  This will only happen if the
+                                assembler did not set up the .bf
+                                endndx symbols correctly.  */
+                             auxout = (PTR) (finfo->outsyms
+                                             + ((finfo->last_bf_index
+                                                 - syment_base)
+                                                * osymesz));
+                             bfd_coff_swap_aux_out (output_bfd,
+                                                    (PTR) &finfo->last_bf,
+                                                    isymp->n_type,
+                                                    isymp->n_sclass,
+                                                    0, isymp->n_numaux,
+                                                    auxout);
+                           }
+                         else
+                           {
+                             /* We have already written out the last
+                                 .bf aux entry.  We need to write it
+                                 out again.  We borrow *outsym
+                                 temporarily.  FIXME: This case should
+                                 be made faster.  */
+                             bfd_coff_swap_aux_out (output_bfd,
+                                                    (PTR) &finfo->last_bf,
+                                                    isymp->n_type,
+                                                    isymp->n_sclass,
+                                                    0, isymp->n_numaux,
+                                                    (PTR) outsym);
+                             if (bfd_seek (output_bfd,
+                                           (obj_sym_filepos (output_bfd)
+                                            + finfo->last_bf_index * osymesz),
+                                           SEEK_SET) != 0
+                                 || bfd_write (outsym, osymesz, 1,
+                                               output_bfd) != osymesz)
+                               return false;
+                           }
+                       }
+
+                     if (auxp->x_sym.x_fcnary.x_fcn.x_endndx.l != 0)
+                       finfo->last_bf_index = -1;
+                     else
+                       {
+                         /* The endndx field of this aux entry must
+                             be updated with the symbol number of the
+                             next .bf symbol.  */
+                         finfo->last_bf = *auxp;
+                         finfo->last_bf_index = (((outsym - finfo->outsyms)
+                                                  / osymesz)
+                                                 + syment_base);
+                       }
+                   }
                }
 
              if (h == NULL)
                }
 
              if (h == NULL)
@@ -1735,8 +2014,16 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
   for (o = input_bfd->sections; o != NULL; o = o->next)
     {
       bfd_byte *contents;
   for (o = input_bfd->sections; o != NULL; o = o->next)
     {
       bfd_byte *contents;
+      struct coff_section_tdata *secdata;
 
 
-      if ((o->flags & SEC_HAS_CONTENTS) == 0)
+      if (! o->linker_mark)
+       {
+         /* This section was omitted from the link.  */
+         continue;
+       }
+
+      if ((o->flags & SEC_HAS_CONTENTS) == 0
+         || (o->_raw_size == 0 && (o->flags & SEC_RELOC) == 0))
        {
          if ((o->flags & SEC_RELOC) != 0
              && o->reloc_count != 0)
        {
          if ((o->flags & SEC_RELOC) != 0
              && o->reloc_count != 0)
@@ -1752,9 +2039,9 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
          continue;
        }
 
          continue;
        }
 
-      if (coff_section_data (input_bfd, o) != NULL
-         && coff_section_data (input_bfd, o)->contents != NULL)
-       contents = coff_section_data (input_bfd, o)->contents;
+      secdata = coff_section_data (input_bfd, o);
+      if (secdata != NULL && secdata->contents != NULL)
+       contents = secdata->contents;
       else
        {
          if (! bfd_get_section_contents (input_bfd, o, finfo->contents,
       else
        {
          if (! bfd_get_section_contents (input_bfd, o, finfo->contents,
@@ -1858,9 +2145,10 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
                          char buf[SYMNMLEN + 1];
 
                          /* This reloc is against a symbol we are
                          char buf[SYMNMLEN + 1];
 
                          /* This reloc is against a symbol we are
-                             stripping.  It would be possible to
-                             handle this case, but I don't think it's
-                             worth it.  */
+                             stripping.  This should have been handled
+                            by the 'dont_skip_symbol' code in the while
+                            loop at the top of this function. */
+                         
                          is = finfo->internal_syms + irel->r_symndx;
 
                          name = (_bfd_coff_internal_syment_name
                          is = finfo->internal_syms + irel->r_symndx;
 
                          name = (_bfd_coff_internal_syment_name
@@ -1881,12 +2169,22 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
        }
 
       /* Write out the modified section contents.  */
        }
 
       /* Write out the modified section contents.  */
-      if (! bfd_set_section_contents (output_bfd, o->output_section,
-                                     contents, o->output_offset,
-                                     (o->_cooked_size != 0
-                                      ? o->_cooked_size
-                                      : o->_raw_size)))
-       return false;
+      if (secdata == NULL || secdata->stab_info == NULL)
+       {
+         if (! bfd_set_section_contents (output_bfd, o->output_section,
+                                         contents, o->output_offset,
+                                         (o->_cooked_size != 0
+                                          ? o->_cooked_size
+                                          : o->_raw_size)))
+           return false;
+       }
+      else
+       {
+         if (! (_bfd_write_section_stabs
+                (output_bfd, &coff_hash_table (finfo->info)->stab_info,
+                 o, &secdata->stab_info, contents)))
+           return false;
+       }
     }
 
   if (! finfo->info->keep_memory)
     }
 
   if (! finfo->info->keep_memory)
@@ -1948,8 +2246,9 @@ _bfd_coff_write_global_sym (h, data)
        else
          isym.n_scnum = sec->target_index;
        isym.n_value = (h->root.u.def.value
        else
          isym.n_scnum = sec->target_index;
        isym.n_value = (h->root.u.def.value
-                       + sec->vma
                        + h->root.u.def.section->output_offset);
                        + h->root.u.def.section->output_offset);
+       if (! obj_pe (finfo->output_bfd))
+         isym.n_value += sec->vma;
       }
       break;
 
       }
       break;
 
@@ -2119,9 +2418,10 @@ _bfd_coff_reloc_link_order (output_bfd, finfo, output_section, link_order)
     {
       struct coff_link_hash_entry *h;
 
     {
       struct coff_link_hash_entry *h;
 
-      h = coff_link_hash_lookup (coff_hash_table (finfo->info),
-                                link_order->u.reloc.p->u.name,
-                                false, false, true);
+      h = ((struct coff_link_hash_entry *)
+          bfd_wrapped_link_hash_lookup (output_bfd, finfo->info,
+                                        link_order->u.reloc.p->u.name,
+                                        false, false, true));
       if (h != NULL)
        {
          if (h->indx >= 0)
       if (h != NULL)
        {
          if (h->indx >= 0)
@@ -2218,6 +2518,18 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
       if (howto == NULL)
        return false;
 
       if (howto == NULL)
        return false;
 
+      /* If we are doing a relocateable link, then we can just ignore
+         a PC relative reloc that is pcrel_offset.  It will already
+         have the correct value.  If this is not a relocateable link,
+         then we should ignore the symbol value.  */
+      if (howto->pc_relative && howto->pcrel_offset)
+       {
+         if (info->relocateable)
+           continue;
+         if (sym != NULL && sym->n_scnum != 0)
+           addend += sym->n_value;
+       }
+
       val = 0;
 
       if (h == NULL)
       val = 0;
 
       if (h == NULL)
@@ -2234,8 +2546,9 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
              sec = sections[symndx];
               val = (sec->output_section->vma
                     + sec->output_offset
              sec = sections[symndx];
               val = (sec->output_section->vma
                     + sec->output_offset
-                    + sym->n_value
-                    - sec->vma);
+                    + sym->n_value);
+             if (! obj_pe (output_bfd))
+               val -= sec->vma;
            }
        }
       else
            }
        }
       else
@@ -2274,6 +2587,7 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
                  + input_section->output_section->vma;
              if (coff_data(output_bfd)->pe)
                addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
                  + input_section->output_section->vma;
              if (coff_data(output_bfd)->pe)
                addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
+             /* FIXME: Shouldn't 4 be sizeof (addr)?  */
              fwrite (&addr, 1,4, (FILE *) info->base_file);
            }
        }
              fwrite (&addr, 1,4, (FILE *) info->base_file);
            }
        }
@@ -2289,6 +2603,13 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
          abort ();
        case bfd_reloc_ok:
          break;
          abort ();
        case bfd_reloc_ok:
          break;
+       case bfd_reloc_outofrange:
+         (*_bfd_error_handler)
+           ("%s: bad reloc address 0x%lx in section `%s'",
+            bfd_get_filename (input_bfd),
+            (unsigned long) rel->r_vaddr,
+            bfd_get_section_name (input_bfd, input_section));
+         return false;
        case bfd_reloc_overflow:
          {
            const char *name;
        case bfd_reloc_overflow:
          {
            const char *name;
This page took 0.03345 seconds and 4 git commands to generate.