Updates.
[deliverable/binutils-gdb.git] / bfd / cofflink.c
index 9344a04e4409e28697079281b5830f914cfa3ef3..8c825968dd56ab8345db866b6d07ee443fac30a8 100644 (file)
@@ -40,6 +40,15 @@ static int process_embedded_commands
   PARAMS ((bfd *, struct bfd_link_info *, bfd *));
 static void mark_relocs PARAMS ((struct coff_final_link_info *, bfd *));
 
+/* Return true if SYM is a weak, external symbol.  */
+#define IS_WEAK_EXTERNAL(abfd, sym)                    \
+  ((sym).n_sclass == C_WEAKEXT                         \
+   || (obj_pe (abfd) && (sym).n_sclass == C_NT_WEAK))
+
+/* Return true if SYM is an external symbol.  */
+#define IS_EXTERNAL(abfd, sym)                         \
+  ((sym).n_sclass == C_EXT || IS_WEAK_EXTERNAL (abfd, sym))
+
 /* Define macros so that the ISFCN, et. al., macros work correctly.
    These macros are defined in include/coff/internal.h in terms of
    N_TMASK, etc.  These definitions require a user to define local
@@ -395,8 +404,7 @@ coff_link_add_symbols (abfd, info)
              break;
            }
 
-         if (sym.n_sclass == C_WEAKEXT
-             || (obj_pe (abfd) && sym.n_sclass == C_NT_WEAK))
+         if (IS_WEAK_EXTERNAL (abfd, sym))
            flags = BSF_WEAK;
 
          addit = true;
@@ -422,6 +430,46 @@ coff_link_add_symbols (abfd, info)
                }
            }
 
+         /* The Microsoft Visual C compiler does string pooling by
+            hashing the constants to an internal symbol name, and
+            relying on the the linker comdat support to discard
+            duplicate names.  However, if one string is a literal and
+            one is a data initializer, one will end up in the .data
+            section and one will end up in the .rdata section.  The
+            Microsoft linker will combine them into the .data
+            section, which seems to be wrong since it might cause the
+            literal to change.
+
+            As long as there are no external references to the
+            symbols, which there shouldn't be, we can treat the .data
+            and .rdata instances as separate symbols.  The comdat
+            code in the linker will do the appropriate merging.  Here
+            we avoid getting a multiple definition error for one of
+            these special symbols.
+
+            FIXME: I don't think this will work in the case where
+            there are two object files which use the constants as a
+            literal and two object files which use it as a data
+            initializer.  One or the other of the second object files
+            is going to wind up with an inappropriate reference.  */
+         if (obj_pe (abfd)
+             && (classification == COFF_SYMBOL_GLOBAL
+                 || classification == COFF_SYMBOL_PE_SECTION)
+             && section->comdat != NULL
+             && strncmp (name, "??_", 3) == 0
+             && strcmp (name, section->comdat->name) == 0)
+           {
+             if (*sym_hash == NULL)
+               *sym_hash = coff_link_hash_lookup (coff_hash_table (info),
+                                                  name, false, copy, false);
+             if (*sym_hash != NULL
+                 && (*sym_hash)->root.type == bfd_link_hash_defined
+                 && (*sym_hash)->root.u.def.section->comdat != NULL
+                 && strcmp ((*sym_hash)->root.u.def.section->comdat->name,
+                            section->comdat->name) == 0)
+               addit = false;
+           }
+
          if (addit)
            {
              if (! (bfd_coff_link_add_one_symbol
@@ -854,8 +902,7 @@ _bfd_coff_final_link (abfd, info)
       for (p = o->link_order_head; p != NULL; p = p->next)
        {
          if (p->type == bfd_indirect_link_order
-             && (bfd_get_flavour (p->u.indirect.section->owner)
-                 == bfd_target_coff_flavour))
+             && bfd_family_coff (p->u.indirect.section->owner))
            {
              sub = p->u.indirect.section->owner;
              if (! bfd_coff_link_output_has_begun (sub, & finfo))
@@ -1689,31 +1736,76 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
              isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx;
            }
 
-         if (isym.n_scnum > 0)
+         switch (isym.n_sclass)
            {
-             isym.n_scnum = (*secpp)->output_section->target_index;
-             isym.n_value += (*secpp)->output_offset;
-             if (! obj_pe (input_bfd))
-               isym.n_value -= (*secpp)->vma;
-             if (! obj_pe (finfo->output_bfd))
-               isym.n_value += (*secpp)->output_section->vma;
-           }
+           case C_AUTO:
+           case C_MOS:
+           case C_EOS:
+           case C_MOE:
+           case C_MOU:
+           case C_UNTAG:
+           case C_STRTAG:
+           case C_ENTAG:
+           case C_TPDEF:
+           case C_ARG:
+           case C_USTATIC:
+           case C_REG:
+           case C_REGPARM:
+           case C_FIELD:
+             /* The symbol value should not be modified.  */
+             break;
+
+           case C_FCN:
+             if (obj_pe (input_bfd)
+                 && strcmp (isym.n_name, ".bf") != 0
+                 && isym.n_scnum > 0)
+               {
+                 /* For PE, .lf and .ef get their value left alone,
+                    while .bf gets relocated.  However, they all have
+                    "real" section numbers, and need to be moved into
+                    the new section.  */
+                 isym.n_scnum = (*secpp)->output_section->target_index;
+                 break;
+               }
+             /* Fall through.  */
+           default:
+           case C_LABEL:  /* Not completely sure about these 2 */
+           case C_EXTDEF:
+           case C_BLOCK:
+           case C_EFCN:
+           case C_NULL:
+           case C_EXT:
+           case C_STAT:
+           case C_SECTION:
+           case C_NT_WEAK:
+             /* Compute new symbol location.  */
+           if (isym.n_scnum > 0)
+             {
+               isym.n_scnum = (*secpp)->output_section->target_index;
+               isym.n_value += (*secpp)->output_offset;
+               if (! obj_pe (input_bfd))
+                 isym.n_value -= (*secpp)->vma;
+               if (! obj_pe (finfo->output_bfd))
+                 isym.n_value += (*secpp)->output_section->vma;
+             }
+           break;
+
+           case C_FILE:
+             /* The value of a C_FILE symbol is the symbol index of
+                the next C_FILE symbol.  The value of the last C_FILE
+                symbol is the symbol index to the first external
+                symbol (actually, coff_renumber_symbols does not get
+                this right--it just sets the value of the last C_FILE
+                symbol to zero--and nobody has ever complained about
+                it).  We try to get this right, below, just before we
+                write the symbols out, but in the general case we may
+                have to write the symbol out twice.  */
 
-         /* The value of a C_FILE symbol is the symbol index of the
-            next C_FILE symbol.  The value of the last C_FILE symbol
-            is the symbol index to the first external symbol
-            (actually, coff_renumber_symbols does not get this
-            right--it just sets the value of the last C_FILE symbol
-            to zero--and nobody has ever complained about it).  We
-            try to get this right, below, just before we write the
-            symbols out, but in the general case we may have to write
-            the symbol out twice.  */
-         if (isym.n_sclass == C_FILE)
-           {
              if (finfo->last_file_index != -1
                  && finfo->last_file.n_value != (long) output_index)
                {
-                 /* We must correct the value of the last C_FILE entry.  */
+                 /* We must correct the value of the last C_FILE
+                     entry.  */
                  finfo->last_file.n_value = output_index;
                  if ((bfd_size_type) finfo->last_file_index >= syment_base)
                    {
@@ -1745,15 +1837,12 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
 
              finfo->last_file_index = output_index;
              finfo->last_file = isym;
+             break;
            }
 
          /* If doing task linking, convert normal global function symbols to
-            static functions. */
-
-         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)))
+            static functions.  */
+         if (finfo->info->task_link && IS_EXTERNAL (input_bfd, isym))
            isym.n_sclass = C_STAT;
 
          /* Output the symbol.  */
@@ -2116,7 +2205,7 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
                                                 is.n_numaux, auxptr);
                        }
 
-                       skipping = false;
+                     skipping = false;
                    }
 
                  iline.l_addr.l_symndx = indx;
@@ -2339,7 +2428,10 @@ _bfd_coff_link_input_bfd (finfo, input_bfd)
       if (secdata == NULL || secdata->stab_info == NULL)
        {
          if (! bfd_set_section_contents (output_bfd, o->output_section,
-                                         contents, o->output_offset,
+                                         contents, 
+                                          (file_ptr) 
+                                          (o->output_offset * 
+                                           bfd_octets_per_byte (output_bfd)),
                                          (o->_cooked_size != 0
                                           ? o->_cooked_size
                                           : o->_raw_size)))
@@ -2460,18 +2552,23 @@ _bfd_coff_write_global_sym (h, data)
   /* 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. */
+     output during a later pass.  */
   if (finfo->global_to_static)
     {
-      if (isym.n_sclass != C_EXT
-         && isym.n_sclass != C_WEAKEXT
-         && (! obj_pe (output_bfd) || isym.n_sclass != C_NT_WEAK))
-       {
-         return true;
-       }
+      if (! IS_EXTERNAL (output_bfd, isym))
+       return true;
+
       isym.n_sclass = C_STAT;
     }
 
+  /* When a weak symbol is not overriden by a strong one,
+     turn it into an external symbol when not building a
+     shared or relocateable object.  */
+  if (! finfo->info->shared
+      && ! finfo->info->relocateable
+      && IS_WEAK_EXTERNAL (finfo->output_bfd, isym))
+    isym.n_sclass = C_EXT;
+
   isym.n_numaux = h->numaux;
   
   bfd_coff_swap_sym_out (output_bfd, (PTR) &isym, (PTR) finfo->outsyms);
@@ -2651,7 +2748,9 @@ _bfd_coff_reloc_link_order (output_bfd, finfo, output_section, link_order)
          break;
        }
       ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf,
-                                    (file_ptr) link_order->offset, size);
+                                    (file_ptr) 
+                                     (link_order->offset *
+                                      bfd_octets_per_byte (output_bfd)), size);
       free (buf);
       if (! ok)
        return false;
@@ -2842,7 +2941,7 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
            {
              if (! ((*info->callbacks->undefined_symbol)
                     (info, h->root.root.string, input_bfd, input_section,
-                     rel->r_vaddr - input_section->vma)))
+                     rel->r_vaddr - input_section->vma, true)))
                return false;
            }
        }
This page took 0.026077 seconds and 4 git commands to generate.