1999-08-08 Mark Elbrecht <snowball3@bigfoot.com>
[deliverable/binutils-gdb.git] / bfd / cofflink.c
index 2f19641289a578381411d52a54f50d02b0a8c843..c9d23f23d3cf251f83457534c1b2e825f975c472 100644 (file)
@@ -1,5 +1,5 @@
 /* COFF specific linker code.
 /* COFF specific linker code.
-   Copyright 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999 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.
@@ -225,30 +225,25 @@ coff_link_check_ar_symbols (abfd, info, pneeded)
      struct bfd_link_info *info;
      boolean *pneeded;
 {
      struct bfd_link_info *info;
      boolean *pneeded;
 {
-  boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *));
   bfd_size_type symesz;
   bfd_byte *esym;
   bfd_byte *esym_end;
 
   *pneeded = false;
 
   bfd_size_type symesz;
   bfd_byte *esym;
   bfd_byte *esym_end;
 
   *pneeded = false;
 
-  sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global;
-
   symesz = bfd_coff_symesz (abfd);
   esym = (bfd_byte *) obj_coff_external_syms (abfd);
   esym_end = esym + obj_raw_syment_count (abfd) * symesz;
   while (esym < esym_end)
     {
       struct internal_syment sym;
   symesz = bfd_coff_symesz (abfd);
   esym = (bfd_byte *) obj_coff_external_syms (abfd);
   esym_end = esym + obj_raw_syment_count (abfd) * symesz;
   while (esym < esym_end)
     {
       struct internal_syment sym;
+      enum coff_symbol_classification classification;
 
       bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym);
 
 
       bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym);
 
-      if ((sym.n_sclass == C_EXT
-#ifdef C_SYSTEM
-          || sym.n_sclass == C_SYSTEM
-#endif
-          || (sym_is_global && (*sym_is_global) (abfd, &sym)))
-         && (sym.n_scnum != 0 || sym.n_value != 0))
+      classification = bfd_coff_classify_symbol (abfd, &sym);
+      if (classification == COFF_SYMBOL_GLOBAL
+         || classification == COFF_SYMBOL_COMMON)
        {
          const char *name;
          char buf[SYMNMLEN + 1];
        {
          const char *name;
          char buf[SYMNMLEN + 1];
@@ -290,7 +285,6 @@ coff_link_add_symbols (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
      bfd *abfd;
      struct bfd_link_info *info;
 {
-  boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *));
   boolean keep_syms;
   boolean default_copy;
   bfd_size_type symcount;
   boolean keep_syms;
   boolean default_copy;
   bfd_size_type symcount;
@@ -304,8 +298,6 @@ coff_link_add_symbols (abfd, info)
   keep_syms = obj_coff_keep_syms (abfd);
   obj_coff_keep_syms (abfd) = true;
 
   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)
     default_copy = false;
   else
   if (info->keep_memory)
     default_copy = false;
   else
@@ -332,21 +324,20 @@ coff_link_add_symbols (abfd, info)
   while (esym < esym_end)
     {
       struct internal_syment sym;
   while (esym < esym_end)
     {
       struct internal_syment sym;
+      enum coff_symbol_classification classification;
       boolean copy;
 
       bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym);
 
       boolean copy;
 
       bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym);
 
-      if (sym.n_sclass == C_EXT
-#ifdef C_SYSTEM
-         || sym.n_sclass == C_SYSTEM
-#endif
-         || (sym_is_global && (*sym_is_global) (abfd, &sym)))
+      classification = bfd_coff_classify_symbol (abfd, &sym);
+      if (classification != COFF_SYMBOL_LOCAL)
        {
          const char *name;
          char buf[SYMNMLEN + 1];
          flagword flags;
          asection *section;
          bfd_vma value;
        {
          const char *name;
          char buf[SYMNMLEN + 1];
          flagword flags;
          asection *section;
          bfd_vma value;
+         boolean addit;
 
          /* This symbol is externally visible.  */
 
 
          /* This symbol is externally visible.  */
 
@@ -363,32 +354,73 @@ coff_link_add_symbols (abfd, info)
 
          value = sym.n_value;
 
 
          value = sym.n_value;
 
-         if (sym.n_scnum == 0)
-           {
-             if (value == 0)
-               {
-                 flags = 0;
-                 section = bfd_und_section_ptr;
-               }
-             else
-               {
-                 flags = BSF_GLOBAL;
-                 section = bfd_com_section_ptr;
-               }
-           }
-         else
+         switch (classification)
            {
            {
+           default:
+             abort ();
+
+           case COFF_SYMBOL_GLOBAL:
              flags = BSF_EXPORT | BSF_GLOBAL;
              section = coff_section_from_bfd_index (abfd, sym.n_scnum);
              if (! obj_pe (abfd))
                value -= section->vma;
              flags = BSF_EXPORT | BSF_GLOBAL;
              section = coff_section_from_bfd_index (abfd, sym.n_scnum);
              if (! obj_pe (abfd))
                value -= section->vma;
+             break;
+
+           case COFF_SYMBOL_UNDEFINED:
+             flags = 0;
+             section = bfd_und_section_ptr;
+             break;
+
+           case COFF_SYMBOL_COMMON:
+             flags = BSF_GLOBAL;
+             section = bfd_com_section_ptr;
+             break;
+
+           case COFF_SYMBOL_PE_SECTION:
+             flags = BSF_SECTION_SYM | BSF_GLOBAL;
+             section = coff_section_from_bfd_index (abfd, sym.n_scnum);
+             break;
            }
 
            }
 
-         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)))
-           goto error_return;
+         if (sym.n_sclass == C_WEAKEXT
+             || (obj_pe (abfd) && sym.n_sclass == C_NT_WEAK))
+           flags = BSF_WEAK;
+
+         addit = true;
+
+         /* In the PE format, section symbols actually refer to the
+             start of the output section.  We handle them specially
+             here.  */
+         if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0)
+           {
+             *sym_hash = coff_link_hash_lookup (coff_hash_table (info),
+                                                name, false, copy, false);
+             if (*sym_hash != NULL)
+               {
+                 if (((*sym_hash)->coff_link_hash_flags
+                      & COFF_LINK_HASH_PE_SECTION_SYMBOL) == 0
+                     && (*sym_hash)->root.type != bfd_link_hash_undefined
+                     && (*sym_hash)->root.type != bfd_link_hash_undefweak)
+                   (*_bfd_error_handler)
+                     ("Warning: symbol `%s' is both section and non-section",
+                      name);
+
+                 addit = false;
+               }
+           }
+
+         if (addit)
+           {
+             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)))
+               goto error_return;
+           }
+
+         if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0)
+           (*sym_hash)->coff_link_hash_flags |=
+             COFF_LINK_HASH_PE_SECTION_SYMBOL;
 
          if (section == bfd_com_section_ptr
              && (*sym_hash)->root.type == bfd_link_hash_common
 
          if (section == bfd_com_section_ptr
              && (*sym_hash)->root.type == bfd_link_hash_common
@@ -403,7 +435,8 @@ coff_link_add_symbols (abfd, info)
                   && (*sym_hash)->type == T_NULL)
                  || sym.n_scnum != 0
                  || (sym.n_value != 0
                   && (*sym_hash)->type == T_NULL)
                  || sym.n_scnum != 0
                  || (sym.n_value != 0
-                     && (*sym_hash)->root.type != bfd_link_hash_defined))
+                     && (*sym_hash)->root.type != bfd_link_hash_defined
+                     && (*sym_hash)->root.type != bfd_link_hash_defweak))
                {
                  (*sym_hash)->class = sym.n_sclass;
                  if (sym.n_type != T_NULL)
                {
                  (*sym_hash)->class = sym.n_sclass;
                  if (sym.n_type != T_NULL)
@@ -411,7 +444,7 @@ coff_link_add_symbols (abfd, info)
                      if ((*sym_hash)->type != T_NULL
                          && (*sym_hash)->type != sym.n_type)
                        (*_bfd_error_handler)
                      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",
+                         (_("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;
                           name, (*sym_hash)->type, sym.n_type,
                           bfd_get_filename (abfd));
                      (*sym_hash)->type = sym.n_type;
@@ -441,6 +474,26 @@ coff_link_add_symbols (abfd, info)
                    }
                }
            }
                    }
                }
            }
+
+         if (classification == COFF_SYMBOL_PE_SECTION
+             && (*sym_hash)->numaux != 0)
+           {
+             /* Some PE sections (such as .bss) have a zero size in
+                 the section header, but a non-zero size in the AUX
+                 record.  Correct that here.
+
+                FIXME: This is not at all the right place to do this.
+                For example, it won't help objdump.  This needs to be
+                done when we swap in the section header.  */
+
+             BFD_ASSERT ((*sym_hash)->numaux == 1);
+             if (section->_raw_size == 0)
+               section->_raw_size = (*sym_hash)->aux[0].x_scn.x_scnlen;
+
+             /* FIXME: We could test whether the section sizes
+                 matches the size in the aux entry, but apparently
+                 that sometimes fails unexpectedly.  */
+           }
        }
 
       esym += (sym.n_numaux + 1) * symesz;
        }
 
       esym += (sym.n_numaux + 1) * symesz;
@@ -1060,7 +1113,7 @@ char **dst;
 static int
 process_embedded_commands (output_bfd, info,  abfd)
      bfd *output_bfd;
 static int
 process_embedded_commands (output_bfd, info,  abfd)
      bfd *output_bfd;
-     struct bfd_link_info *info;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
      bfd *abfd;
 {
   asection *sec = bfd_get_section_by_name (abfd, ".drectve");
      bfd *abfd;
 {
   asection *sec = bfd_get_section_by_name (abfd, ".drectve");
@@ -1203,7 +1256,6 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
      struct coff_final_link_info *finfo;
      bfd *input_bfd;
 {
      struct coff_final_link_info *finfo;
      bfd *input_bfd;
 {
-  boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *));
   boolean (*adjust_symndx) PARAMS ((bfd *, struct bfd_link_info *, bfd *,
                                    asection *, struct internal_reloc *,
                                    boolean *));
   boolean (*adjust_symndx) PARAMS ((bfd *, struct bfd_link_info *, bfd *,
                                    asection *, struct internal_reloc *,
                                    boolean *));
@@ -1229,7 +1281,6 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
   /* Move all the symbols to the output file.  */
 
   output_bfd = finfo->output_bfd;
   /* Move all the symbols to the output file.  */
 
   output_bfd = finfo->output_bfd;
-  sym_is_global = coff_backend_info (input_bfd)->_bfd_coff_sym_is_global;
   strings = NULL;
   syment_base = obj_raw_syment_count (output_bfd);
   isymesz = bfd_coff_symesz (input_bfd);
   strings = NULL;
   syment_base = obj_raw_syment_count (output_bfd);
   isymesz = bfd_coff_symesz (input_bfd);
@@ -1284,6 +1335,7 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
   while (esym < esym_end)
     {
       struct internal_syment isym;
   while (esym < esym_end)
     {
       struct internal_syment isym;
+      enum coff_symbol_classification classification;
       boolean skip;
       boolean global;
       boolean dont_skip_symbol;
       boolean skip;
       boolean global;
       boolean dont_skip_symbol;
@@ -1297,14 +1349,22 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
         the symbol.  */
       isym = *isymp;
 
         the symbol.  */
       isym = *isymp;
 
-      if (isym.n_scnum != 0)
-       *secpp = coff_section_from_bfd_index (input_bfd, isym.n_scnum);
-      else
+      classification = bfd_coff_classify_symbol (input_bfd, &isym);
+      switch (classification)
        {
        {
-         if (isym.n_value == 0)
-           *secpp = bfd_und_section_ptr;
-         else
-           *secpp = bfd_com_section_ptr;
+       default:
+         abort ();
+       case COFF_SYMBOL_GLOBAL:
+       case COFF_SYMBOL_PE_SECTION:
+       case COFF_SYMBOL_LOCAL:
+         *secpp = coff_section_from_bfd_index (input_bfd, isym.n_scnum);
+         break;
+       case COFF_SYMBOL_COMMON:
+         *secpp = bfd_com_section_ptr;
+         break;
+       case COFF_SYMBOL_UNDEFINED:
+         *secpp = bfd_und_section_ptr;
+         break;
        }
 
       /* Extract the flag indicating if this symbol is used by a
        }
 
       /* Extract the flag indicating if this symbol is used by a
@@ -1328,26 +1388,34 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
 
       if (! skip)
        {
 
       if (! skip)
        {
-         if (isym.n_sclass == C_EXT
-#ifdef C_SYSTEM
-             || isym.n_sclass == C_SYSTEM
-#endif
-             || (sym_is_global && (*sym_is_global) (input_bfd, &isym)))
+         switch (classification)
            {
            {
+           default:
+             abort ();
+           case COFF_SYMBOL_GLOBAL:
+           case COFF_SYMBOL_COMMON:
+           case COFF_SYMBOL_PE_SECTION:
              /* This is a global symbol.  Global symbols come at the
                 end of the symbol table, so skip them for now.
              /* This is a global symbol.  Global symbols come at the
                 end of the symbol table, so skip them for now.
-                Function symbols, however, are an exception, and are
-                not moved to the end.  */
+                Locally defined function symbols, however, are an
+                exception, and are not moved to the end.  */
              global = true;
              if (! ISFCN (isym.n_type))
                skip = true;
              global = true;
              if (! ISFCN (isym.n_type))
                skip = true;
-           }
-         else
-           {
+             break;
+
+           case COFF_SYMBOL_UNDEFINED:
+             /* Undefined symbols are left for the end.  */
+             global = true;
+             skip = true;
+             break;
+
+           case COFF_SYMBOL_LOCAL:
              /* This is a local symbol.  Skip it if we are discarding
                  local symbols.  */
              if (finfo->info->discard == discard_all && ! dont_skip_symbol)
                skip = true;
              /* This is a local symbol.  Skip it if we are discarding
                  local symbols.  */
              if (finfo->info->discard == discard_all && ! dont_skip_symbol)
                skip = true;
+             break;
            }
        }
 
            }
        }
 
@@ -1648,7 +1716,10 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
          /* If doing task linking, convert normal global function symbols to
             static functions. */
 
          /* If doing task linking, convert normal global function symbols to
             static functions. */
 
-         if (finfo->info->task_link && isym.n_sclass == C_EXT)
+         if (finfo->info->task_link
+             && (isym.n_sclass == C_EXT
+                 || isym.n_sclass == C_WEAKEXT
+                 || (obj_pe (input_bfd) && isym.n_sclass == C_NT_WEAK)))
            isym.n_sclass = C_STAT;
 
          /* Output the symbol.  */
            isym.n_sclass = C_STAT;
 
          /* Output the symbol.  */
@@ -2076,7 +2147,7 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
              && o->reloc_count != 0)
            {
              ((*_bfd_error_handler)
              && o->reloc_count != 0)
            {
              ((*_bfd_error_handler)
-              ("%s: relocs in section `%s', but it has no contents",
+              (_("%s: relocs in section `%s', but it has no contents"),
                bfd_get_filename (input_bfd),
                bfd_get_section_name (input_bfd, o)));
              bfd_set_error (bfd_error_no_contents);
                bfd_get_filename (input_bfd),
                bfd_get_section_name (input_bfd, o)));
              bfd_set_error (bfd_error_no_contents);
@@ -2337,12 +2408,15 @@ _bfd_coff_write_global_sym (h, data)
   if (isym.n_sclass == C_NULL)
     isym.n_sclass = C_EXT;
 
   if (isym.n_sclass == C_NULL)
     isym.n_sclass = C_EXT;
 
-  /* If doing task linking and this is the pass where we convert defined globals to
-     statics, then do that conversion now.  If the symbol is not being converted,
-     just ignore it and it will be output during a later pass. */
+  /* If doing task linking and this is the pass where we convert
+     defined globals to statics, then do that conversion now.  If the
+     symbol is not being converted, just ignore it and it will be
+     output during a later pass. */
   if (finfo->global_to_static)
     {
   if (finfo->global_to_static)
     {
-      if (isym.n_sclass != C_EXT)
+      if (isym.n_sclass != C_EXT
+         && isym.n_sclass != C_WEAKEXT
+         && (! obj_pe (output_bfd) || isym.n_sclass != C_NT_WEAK))
        {
          return true;
        }
        {
          return true;
        }
@@ -2586,6 +2660,14 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
          h = NULL;
          sym = NULL;
        }
          h = NULL;
          sym = NULL;
        }
+      else if (symndx < 0
+              || (unsigned long) symndx >= obj_raw_syment_count (input_bfd))
+       {
+         (*_bfd_error_handler)
+           ("%s: illegal symbol index %ld in relocs",
+            bfd_get_filename (input_bfd), symndx);
+         return false;
+       }
       else
        {    
          h = obj_coff_sym_hashes (input_bfd)[symndx];
       else
        {    
          h = obj_coff_sym_hashes (input_bfd)[symndx];
@@ -2702,7 +2784,7 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
          break;
        case bfd_reloc_outofrange:
          (*_bfd_error_handler)
          break;
        case bfd_reloc_outofrange:
          (*_bfd_error_handler)
-           ("%s: bad reloc address 0x%lx in section `%s'",
+           (_("%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));
             bfd_get_filename (input_bfd),
             (unsigned long) rel->r_vaddr,
             bfd_get_section_name (input_bfd, input_section));
This page took 0.027614 seconds and 4 git commands to generate.