* coffcode.h (coff_slurp_symbol_table): If COFF_WITH_PE or
[deliverable/binutils-gdb.git] / bfd / cofflink.c
index 9d6201340f25b8b0136afb22133b9bcc88664b9a..c721bdf9de1fa75588eea9f1ee5e0baf0bedd939 100644 (file)
@@ -1,5 +1,5 @@
 /* COFF specific linker code.
-   Copyright 1994, 1995, 1996 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.
@@ -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 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.  */
 
@@ -283,6 +287,7 @@ coff_link_add_symbols (abfd, info)
      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;
@@ -290,6 +295,11 @@ coff_link_add_symbols (abfd, info)
   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)
@@ -306,7 +316,7 @@ coff_link_add_symbols (abfd, info)
                         ((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 *));
@@ -335,7 +345,7 @@ coff_link_add_symbols (abfd, info)
 
          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.  */
@@ -370,7 +380,14 @@ coff_link_add_symbols (abfd, info)
                 (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))
            {
@@ -405,7 +422,7 @@ coff_link_add_symbols (abfd, info)
                                                  (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++)
@@ -448,7 +465,7 @@ coff_link_add_symbols (abfd, info)
                    (PTR) bfd_zalloc (abfd,
                                      sizeof (struct coff_section_tdata));
                  if (stab->used_by_bfd == NULL)
-                   return false;
+                   goto error_return;
                  secdata = coff_section_data (abfd, stab);
                }
 
@@ -457,12 +474,18 @@ coff_link_add_symbols (abfd, info)
              if (! _bfd_link_section_stabs (abfd, &table->stab_info,
                                             stab, stabstr,
                                             &secdata->stab_info))
-               return false;
+               goto error_return;
            }
        }
     }
 
+  obj_coff_keep_syms (abfd) = keep_syms;
+
   return true;
+
+ error_return:
+  obj_coff_keep_syms (abfd) = keep_syms;
+  return false;
 }
 \f
 /* Do the final link step.  */
@@ -521,7 +544,10 @@ _bfd_coff_final_link (abfd, info)
 
   /* 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.  */
@@ -826,7 +852,7 @@ _bfd_coff_final_link (abfd, info)
       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
@@ -1091,6 +1117,60 @@ process_embedded_commands (output_bfd, info,  abfd)
   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.  */
 
@@ -1164,11 +1244,25 @@ _bfd_coff_link_input_bfd (finfo, 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;
+      boolean dont_skip_symbol;
       int add;
 
       bfd_coff_swap_sym_in (input_bfd, (PTR) esym, (PTR) isymp);
@@ -1189,6 +1283,14 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
            *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;
@@ -1196,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.  */
-      if (finfo->info->strip == strip_all)
+      if (finfo->info->strip == strip_all && ! dont_skip_symbol)
        skip = true;
 
       if (! skip)
@@ -1216,7 +1318,7 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
            {
              /* 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;
            }
        }
@@ -1225,6 +1327,7 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
          symbol, then skip it.  */
       if (! skip
          && finfo->info->strip == strip_debugger
+         && ! dont_skip_symbol
          && isym.n_scnum == N_DEBUG)
        skip = true;
 
@@ -1241,13 +1344,13 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
          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))
-             || (! 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;
        }
 
@@ -1447,9 +1550,10 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
          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
@@ -1514,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];
-             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;
            }
 
@@ -2035,9 +2145,10 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
                          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
@@ -2069,8 +2180,9 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
        }
       else
        {
-         if (! _bfd_write_section_stabs (output_bfd, o, &secdata->stab_info,
-                                         contents))
+         if (! (_bfd_write_section_stabs
+                (output_bfd, &coff_hash_table (finfo->info)->stab_info,
+                 o, &secdata->stab_info, contents)))
            return false;
        }
     }
@@ -2134,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
-                       + sec->vma
                        + h->root.u.def.section->output_offset);
+       if (! obj_pe (finfo->output_bfd))
+         isym.n_value += sec->vma;
       }
       break;
 
@@ -2405,6 +2518,18 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
       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)
@@ -2421,8 +2546,9 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
              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
@@ -2477,6 +2603,13 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
          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;
This page took 0.028191 seconds and 4 git commands to generate.