Fix PR14180 and 14181 (patch from branch)
authorNick Clifton <nickc@redhat.com>
Fri, 5 Dec 1997 19:37:35 +0000 (19:37 +0000)
committerNick Clifton <nickc@redhat.com>
Fri, 5 Dec 1997 19:37:35 +0000 (19:37 +0000)
bfd/ChangeLog
bfd/elf32-v850.c

index e13ad35bfa9fba3192867b6702fbbbbd6d49ad38..cd186c666c9ed15ccc530f0d24fbec4f4cd3dacf 100644 (file)
@@ -1,3 +1,12 @@
+Fri Dec  5 11:13:46 1997  Nick Clifton  <nickc@cygnus.com>
+
+       * elf32-v850.c (v850_elf_reloc, v850_elf_store_addend_in_insn,
+       v850_elf_relocate_section): Fix PR2 14180 and 14181 
+       (v850_elf_section_from_bfd_section, v850_elf_symbol_processing,
+       v850_elf_add_symbol_hook, v850_elf_link_output_symbol_hook,
+       v850_elf_section_from_shdr, v850_elf_fake_sections): New functions
+       (for PR14180) to create and handle special common sections.
+
 Tue Dec  2 10:26:16 1997  Nick Clifton  <nickc@cygnus.com>
 
        * coff-arm.c (TARGET_UNDERSCORE): Revert back to '_'
index 6583ea1dd35d23c4bd72a0de46fd5eac749b8fc9..8e5acf68d1b5e6c4618e01c20ea21c3f25359e4a 100644 (file)
@@ -30,6 +30,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "elf-bfd.h"
 #include "elf/v850.h"
 
+/* sign-extend a 24-bit number */
+#define SEXT24(x)      ((((x) & 0xffffff) ^ (~ 0x7fffff)) + 0x800000)
+      
 static reloc_howto_type *v850_elf_reloc_type_lookup
   PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
 static void v850_elf_info_to_howto_rel
@@ -151,7 +154,7 @@ static reloc_howto_type v850_elf_howto_table[] =
         false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
-        bfd_elf_generic_reloc,         /* special_function */
+        v850_elf_reloc,                /* special_function */
         "R_V850_32",                   /* name */
         true,                          /* partial_inplace */
         0xffffffff,                    /* src_mask */
@@ -498,7 +501,7 @@ v850_elf_check_relocs (abfd, info, sec, relocs)
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   asection *sreloc;
-  enum reloc_type r_type;
+  enum v850_reloc_type r_type;
   int other = 0;
   const char *common = (const char *)0;
 
@@ -528,7 +531,7 @@ v850_elf_check_relocs (abfd, info, sec, relocs)
       else
        h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
-      r_type = (enum reloc_type) ELF32_R_TYPE (rel->r_info);
+      r_type = (enum v850_reloc_type) ELF32_R_TYPE (rel->r_info);
       switch (r_type)
        {
        default:
@@ -639,260 +642,299 @@ v850_elf_check_relocs (abfd, info, sec, relocs)
   return ret;
 }
 
-\f
-/* Insert the addend into the instruction.  */
 static bfd_reloc_status_type
-v850_elf_reloc (abfd, reloc, symbol, data, isection, obfd, err)
-     bfd *       abfd;
-     arelent *   reloc;
-     asymbol *   symbol;
-     PTR         data;
-     asection *  isection;
-     bfd *       obfd;
-     char **     err;
+v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
+     bfd *      abfd;
+     int        r_type;
+     long       addend;
+     bfd_byte * address;
+     boolean    replace;
 {
-  long relocation;
-  long insn;
-
-  
-  /* If there is an output BFD,
-     and the symbol is not a section name (which is only defined at final link time),
-     and either we are not putting the addend into the instruction
-         or the addend is zero, so there is nothing to add into the instruction
-     then just fixup the address and return.  */
-  if (obfd != (bfd *) NULL
-      && (symbol->flags & BSF_SECTION_SYM) == 0
-      && (! reloc->howto->partial_inplace
-         || reloc->addend == 0))
-    {
-      reloc->address += isection->output_offset;
-      return bfd_reloc_ok;
-    }
-#if 0  
-  else if (obfd != NULL)
-    {
-      return bfd_reloc_continue;
-    }
-#endif
-  
-  /* Catch relocs involving undefined symbols.  */
-  if (bfd_is_und_section (symbol->section)
-      && (symbol->flags & BSF_WEAK) == 0
-      && obfd == NULL)
-    return bfd_reloc_undefined;
-
-  /* We handle final linking of some relocs ourselves.  */
-
-  /* Is the address of the relocation really within the section?  */
-  if (reloc->address > isection->_cooked_size)
-    return bfd_reloc_outofrange;
-  
-  /* Work out which section the relocation is targetted at and the
-     initial relocation command value.  */
-  
-  /* Get symbol value.  (Common symbols are special.)  */
-  if (bfd_is_com_section (symbol->section))
-    relocation = 0;
-  else
-    relocation = symbol->value;
-  
-  /* Convert input-section-relative symbol value to absolute + addend.  */
-  relocation += symbol->section->output_section->vma;
-  relocation += symbol->section->output_offset;
-  relocation += reloc->addend;
-  
-  if (reloc->howto->pc_relative == true)
-    {
-      /* Here the variable relocation holds the final address of the
-        symbol we are relocating against, plus any addend.  */
-      relocation -= isection->output_section->vma + isection->output_offset;
-      
-      /* Deal with pcrel_offset */
-      relocation -= reloc->address;
-    }
-  
-  /* I've got no clue... */
-  reloc->addend = 0;   
+  unsigned long insn;
   
-  switch (reloc->howto->type)
+  switch (r_type)
     {
     default:
-      /* fprintf (stderr, "reloc type %d not SUPPORTED\n", reloc->howto->type ); */
+      /* fprintf (stderr, "reloc type %d not SUPPORTED\n", r_type ); */
       return bfd_reloc_notsupported;
       
+    case R_V850_32:
+      if (! replace)
+       addend += bfd_get_32 (abfd, address);
+
+      bfd_put_32 (abfd, addend, address);
+      return bfd_reloc_ok;
+      
     case R_V850_22_PCREL:
-      if (relocation > 0x1fffff || relocation < -0x200000)
+      if (addend > 0x1fffff || addend < -0x200000)
        return bfd_reloc_overflow;
       
-      if ((relocation % 2) != 0)
+      if ((addend % 2) != 0)
        return bfd_reloc_dangerous;
       
-      insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc->address);
+      insn  = bfd_get_32 (abfd, address);
       insn &= ~0xfffe003f;
-      insn |= (((relocation & 0xfffe) << 16)
-              | ((relocation & 0x3f0000) >> 16));
-      bfd_put_32 (abfd, insn, (bfd_byte *)data + reloc->address);
+      insn |= (((addend & 0xfffe) << 16) | ((addend & 0x3f0000) >> 16));
+      bfd_put_32 (abfd, insn, address);
       return bfd_reloc_ok;
       
     case R_V850_9_PCREL:
-      if (relocation > 0xff || relocation < -0x100)
+      if (addend > 0xff || addend < -0x100)
        return bfd_reloc_overflow;
       
-      if ((relocation % 2) != 0)
+      if ((addend % 2) != 0)
        return bfd_reloc_dangerous;
       
-      insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
+      insn  = bfd_get_16 (abfd, address);
       insn &= ~ 0xf870;
-      insn |= ((relocation & 0x1f0) << 7) | ((relocation & 0x0e) << 3);
-      bfd_put_16 (abfd, insn, (bfd_byte *)data + reloc->address);
-      return bfd_reloc_ok;
+      insn |= ((addend & 0x1f0) << 7) | ((addend & 0x0e) << 3);
+      break;
       
     case R_V850_HI16_S:
-      relocation += bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
-      relocation = (relocation >> 16) + ((relocation & 0x8000) != 0);
-      bfd_put_16 (abfd, relocation, (bfd_byte *)data + reloc->address);
-      return bfd_reloc_ok;
+      addend += bfd_get_16 (abfd, address);
+      addend = (addend >> 16) + ((addend & 0x8000) != 0);
+      insn = addend;
+      break;
       
     case R_V850_HI16:
-      relocation += bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
-      relocation = (relocation >> 16);
-      bfd_put_16 (abfd, relocation, (bfd_byte *)data + reloc->address);
-      return bfd_reloc_ok;
+      addend += bfd_get_16 (abfd, address);
+      addend = (addend >> 16);
+      insn = addend;
+      break;
       
     case R_V850_LO16:
-      relocation += (short)bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
+      addend += (short) bfd_get_16 (abfd, address);
       /* Do not complain if value has top bit set, as this has been anticipated.  */
-      bfd_put_16 (abfd, relocation, (bfd_byte *)data + reloc->address);
-      return bfd_reloc_ok;
+      insn = addend;
+      break;
 
     case R_V850_16:
-      relocation += (short)bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
+      replace = false;
       /* drop through */
-      
+            
+/* start-sanitize-v850e */
+    case R_V850_CALLT_16_16_OFFSET:
+/* end-sanitize-v850e */
     case R_V850_SDA_16_16_OFFSET:
     case R_V850_ZDA_16_16_OFFSET:
     case R_V850_TDA_16_16_OFFSET:
-      if ((long)relocation > 0x7fff || (long)relocation < -0x8000)
+      if (! replace)
+       addend += bfd_get_16 (abfd, address);
+      
+      if (addend > 0x7fff || addend < -0x8000)
        return bfd_reloc_overflow;
-      bfd_put_16 (abfd, relocation, (bfd_byte *)data + reloc->address);
-      return bfd_reloc_ok;
+
+      insn = addend;
+      break;
       
     case R_V850_SDA_15_16_OFFSET:
     case R_V850_ZDA_15_16_OFFSET:
-      if ((long)relocation > 0x7ffe || (long)relocation < -0x8000)
+      insn = bfd_get_16 (abfd, address);
+
+      if (! replace)
+       addend += ((insn & 0xfffe) << 1);
+      
+      if (addend > 0x7ffe || addend < -0x8000)
        return bfd_reloc_overflow;
       
-      if (relocation & 1)
+      if (addend & 1)
        return bfd_reloc_dangerous;
       
-      insn  = bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
       insn &= 1;
-      insn |= (relocation >> 1) & ~1;
-      
-      bfd_put_16 (abfd, insn, (bfd_byte *)data + reloc->address);
-      return bfd_reloc_ok;
+      insn |= (addend >> 1) & ~1;
+      break;
       
     case R_V850_TDA_6_8_OFFSET:
-      if ((long) relocation > 0xfc || (long) relocation < 0)
+      insn = bfd_get_16 (abfd, address);
+
+      if (! replace)
+       addend += ((insn & 0x7e) << 1);
+      
+      if (addend > 0xfc || addend < 0)
        return bfd_reloc_overflow;
       
-      if (relocation & 3)
+      if (addend & 3)
        return bfd_reloc_dangerous;
       
-      insn  = bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
       insn &= 0xff81;
-      insn |= (relocation >> 1);
-      
-      bfd_put_16 (abfd, insn, (bfd_byte *)data + reloc->address);
-      return bfd_reloc_ok;
+      insn |= (addend >> 1);
+      break;
       
     case R_V850_TDA_7_8_OFFSET:
-      if ((long) relocation > 0xfe || (long) relocation < 0)
+      insn = bfd_get_16 (abfd, address);
+
+      if (! replace)
+       addend += ((insn & 0x7f) << 1);
+      
+      if (addend > 0xfe || addend < 0)
        return bfd_reloc_overflow;
       
-      if (relocation & 1)
+      if (addend & 1)
        return bfd_reloc_dangerous;
       
-      insn  = bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
       insn &= 0xff80;
-      insn |= (relocation >> 1);
-      
-      bfd_put_16 (abfd, insn, (bfd_byte *)data + reloc->address);
-      return bfd_reloc_ok;
+      insn |= (addend >> 1);
+      break;
       
     case R_V850_TDA_7_7_OFFSET:
-      if ((long) relocation > 0x7f || (long) relocation < 0)
+      insn = bfd_get_16 (abfd, address);
+
+      if (! replace)
+       addend += insn & 0x7f;
+       
+      if (addend > 0x7f || addend < 0)
        return bfd_reloc_overflow;
       
-      insn  = bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
       insn &= 0xff80;
-      insn |= relocation;
-      
-      bfd_put_16 (abfd, insn, (bfd_byte *)data + reloc->address);
-      return bfd_reloc_ok;
+      insn |= addend;
+      break;
       
 /* start-sanitize-v850e */
     case R_V850_TDA_4_5_OFFSET:
-      if ((long) relocation > 0x1e || (long) relocation < 0)
+      insn = bfd_get_16 (abfd, address);
+
+      if (! replace)
+       addend += ((insn & 0xf) << 1);
+      
+      if (addend > 0x1e || addend < 0)
        return bfd_reloc_overflow;
       
-      if (relocation & 1)
+      if (addend & 1)
        return bfd_reloc_dangerous;
       
-      insn  = bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
       insn &= 0xfff0;
-      insn |= (relocation >> 1);
-      
-      bfd_put_16 (abfd, insn, (bfd_byte *)data + reloc->address);
-      return bfd_reloc_ok;
+      insn |= (addend >> 1);
+      break;
       
     case R_V850_TDA_4_4_OFFSET:
-      if ((long) relocation > 0xf || (long) relocation < 0)
+      insn = bfd_get_16 (abfd, address);
+
+      if (! replace)
+       addend += insn & 0xf;
+      
+      if (addend > 0xf || addend < 0)
        return bfd_reloc_overflow;
       
-      insn  = bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
       insn &= 0xfff0;
-      insn |= relocation;
-      
-      bfd_put_16 (abfd, insn, (bfd_byte *)data + reloc->address);
-      return bfd_reloc_ok;
+      insn |= addend;
+      break;
       
     case R_V850_ZDA_16_16_SPLIT_OFFSET:
     case R_V850_SDA_16_16_SPLIT_OFFSET:
-      if ((long) relocation > 0xffff || (long) relocation < 0)
-       return bfd_reloc_overflow;
+      insn = bfd_get_32 (abfd, address);
+
+      if (! replace)
+       addend += ((insn & 0xfffe0000) >> 16) + ((insn & 0x20) >> 5);
       
-      insn  = bfd_get_32 (abfd, (bfd_byte *) data + reloc->address);
+      if (addend > 0xffff || addend < 0)
+       return bfd_reloc_overflow;
       
       insn &= 0x0001ffdf;
-      insn |= (relocation & 1) << 5;
-      insn |= (relocation & ~1) << 16;
+      insn |= (addend & 1) << 5;
+      insn |= (addend & ~1) << 16;
       
-      bfd_put_32 (abfd, insn, (bfd_byte *)data + reloc->address);
+      bfd_put_32 (abfd, insn, address);
       return bfd_reloc_ok;
       
     case R_V850_CALLT_6_7_OFFSET:
-      if ((long) relocation > 0x7e || (long) relocation < 0)
+      insn = bfd_get_16 (abfd, address);
+
+      if (! replace)
+        addend += ((insn & 0x3f) << 1);
+      
+      if (addend > 0x7e || addend < 0)
        return bfd_reloc_overflow;
       
-      if (relocation & 1)
+      if (addend & 1)
        return bfd_reloc_dangerous;
       
-      insn  = bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
       insn &= 0xff80;
-      insn |= (relocation >> 1);
-      
-      bfd_put_16 (abfd, insn, (bfd_byte *)data + reloc->address);
-      return bfd_reloc_ok;
-      
-    case R_V850_CALLT_16_16_OFFSET:
-      bfd_put_16 (abfd, relocation, (bfd_byte *)data + reloc->address);
+      insn |= (addend >> 1);
+      break;
+/* end-sanitize-v850e */
+    }
+
+  bfd_put_16 (abfd, insn, address);
+  return bfd_reloc_ok;
+}
+
+\f
+/* Insert the addend into the instruction.  */
+static bfd_reloc_status_type
+v850_elf_reloc (abfd, reloc, symbol, data, isection, obfd, err)
+     bfd *       abfd;
+     arelent *   reloc;
+     asymbol *   symbol;
+     PTR         data;
+     asection *  isection;
+     bfd *       obfd;
+     char **     err;
+{
+  long relocation;
+  long insn;
+
+  
+  /* If there is an output BFD,
+     and the symbol is not a section name (which is only defined at final link time),
+     and either we are not putting the addend into the instruction
+         or the addend is zero, so there is nothing to add into the instruction
+     then just fixup the address and return.  */
+  if (obfd != (bfd *) NULL
+      && (symbol->flags & BSF_SECTION_SYM) == 0
+      && (! reloc->howto->partial_inplace
+         || reloc->addend == 0))
+    {
+      reloc->address += isection->output_offset;
       return bfd_reloc_ok;
+    }
+#if 0  
+  else if (obfd != NULL)
+    {
+      return bfd_reloc_continue;
+    }
+#endif
+  
+  /* Catch relocs involving undefined symbols.  */
+  if (bfd_is_und_section (symbol->section)
+      && (symbol->flags & BSF_WEAK) == 0
+      && obfd == NULL)
+    return bfd_reloc_undefined;
+
+  /* We handle final linking of some relocs ourselves.  */
+
+  /* Is the address of the relocation really within the section?  */
+  if (reloc->address > isection->_cooked_size)
+    return bfd_reloc_outofrange;
+  
+  /* Work out which section the relocation is targetted at and the
+     initial relocation command value.  */
+  
+  /* Get symbol value.  (Common symbols are special.)  */
+  if (bfd_is_com_section (symbol->section))
+    relocation = 0;
+  else
+    relocation = symbol->value;
+  
+  /* Convert input-section-relative symbol value to absolute + addend.  */
+  relocation += symbol->section->output_section->vma;
+  relocation += symbol->section->output_offset;
+  relocation += reloc->addend;
+  
+  if (reloc->howto->pc_relative == true)
+    {
+      /* Here the variable relocation holds the final address of the
+        symbol we are relocating against, plus any addend.  */
+      relocation -= isection->output_section->vma + isection->output_offset;
       
-/* end-sanitize-v850e */
+      /* Deal with pcrel_offset */
+      relocation -= reloc->address;
     }
 
-  return bfd_reloc_continue;
+  /* I've got no clue... */
+  reloc->addend = 0;   
+
+  return v850_elf_store_addend_in_insn (abfd, reloc->howto->type, relocation,
+                                       (bfd_byte *) data + reloc->address, true);
 }
 
 \f
@@ -902,9 +944,8 @@ v850_elf_is_local_label_name (abfd, name)
      bfd *         abfd;
      const char *  name;
 {
-  return ((name[0] == '.' && (name[1] == 'L' || name[1] == '.'))
-         || (name[0] == '_' && name[1] == '.' && name[2] == 'L'
-             && name[3] == '_'));
+  return (   (name[0] == '.' && (name[1] == 'L' || name[1] == '.'))
+         || (name[0] == '_' &&  name[1] == '.' && name[2] == 'L' && name[3] == '_'));
 }
 
 \f
@@ -950,9 +991,11 @@ v850_elf_final_link_relocate (howto, input_bfd, output_bfd,
     
     case R_V850_22_PCREL:
       value -= (input_section->output_section->vma
-               + input_section->output_offset);
-      value -= offset;
-    
+               + input_section->output_offset
+               + offset);
+
+      value = SEXT24 (value);  /* Only the bottom 24 bits of the PC are valid */
+      
       if ((long)value > 0x1fffff || (long)value < -0x200000)
        return bfd_reloc_overflow;
 
@@ -1005,7 +1048,7 @@ v850_elf_final_link_relocate (howto, input_bfd, output_bfd,
     case R_V850_ZDA_16_16_OFFSET:
       if (sym_sec == NULL)
        return bfd_reloc_undefined;
-         
+      
       value -= sym_sec->output_section->vma;
       value += (short) bfd_get_16 (input_bfd, hit_data);
 
@@ -1463,7 +1506,29 @@ v850_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
                {
                  sec = local_sections[r_symndx];
+#ifdef USE_REL
+                 /* The Elf_Internal_Rel structure does not have space for the
+                    modified addend value, so we store it in the instruction
+                    instead. */
+
+                 if (sec->output_offset + sym->st_value != 0)
+                   {
+                     if (v850_elf_store_addend_in_insn (input_bfd, r_type,
+                                                        sec->output_offset +
+                                                        sym->st_value,
+                                                        contents + rel->r_offset,
+                                                        false)
+                         != bfd_reloc_ok)
+                       {
+                         info->callbacks->warning
+                           (info,
+                            "Unable to handle relocation during incremental link",
+                            NULL, input_bfd, input_section, rel->r_offset);
+                       }
+                   }
+#else
                  rel->r_addend += sec->output_offset + sym->st_value;
+#endif
                }
            }
 
@@ -1761,6 +1826,239 @@ v850_elf_print_private_bfd_data (abfd, ptr)
   
   return true;
 }
+
+/* V850 ELF uses four common sections.  One is the usual one, and the
+   others are for (small) objects in one of the special data areas:
+   small, tiny and zero.  All the objects are kept together, and then
+   referenced via the gp register, the ep register or the r0 register
+   respectively, which yields smaller, faster assembler code.  This
+   approach is copied from elf32-mips.c.  */
+
+static asection  v850_elf_scom_section;
+static asymbol   v850_elf_scom_symbol;
+static asymbol * v850_elf_scom_symbol_ptr;
+static asection  v850_elf_tcom_section;
+static asymbol   v850_elf_tcom_symbol;
+static asymbol * v850_elf_tcom_symbol_ptr;
+static asection  v850_elf_zcom_section;
+static asymbol   v850_elf_zcom_symbol;
+static asymbol * v850_elf_zcom_symbol_ptr;
+
+
+/* Given a BFD section, try to locate the corresponding ELF section
+   index.  */
+
+static boolean
+v850_elf_section_from_bfd_section (abfd, hdr, sec, retval)
+     bfd *                 abfd;
+     Elf32_Internal_Shdr * hdr;
+     asection *            sec;
+     int *                 retval;
+{
+  if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0)
+    {
+      *retval = SHN_V850_SCOMMON;
+      return true;
+    }
+  if (strcmp (bfd_get_section_name (abfd, sec), ".tcommon") == 0)
+    {
+      *retval = SHN_V850_TCOMMON;
+      return true;
+    }
+  if (strcmp (bfd_get_section_name (abfd, sec), ".zcommon") == 0)
+    {
+      *retval = SHN_V850_ZCOMMON;
+      return true;
+    }
+  return false;
+}
+
+/* Handle the special V850 section numbers that a symbol may use.  */
+
+static void
+v850_elf_symbol_processing (abfd, asym)
+     bfd *     abfd;
+     asymbol * asym;
+{
+  elf_symbol_type * elfsym = (elf_symbol_type *) asym;
+
+  switch (elfsym->internal_elf_sym.st_shndx)
+    {
+    case SHN_V850_SCOMMON:
+      if (v850_elf_scom_section.name == NULL)
+       {
+         /* Initialize the small common section.  */
+         v850_elf_scom_section.name           = ".scommon";
+         v850_elf_scom_section.flags          = SEC_IS_COMMON | SEC_ALLOC | SEC_DATA;
+         v850_elf_scom_section.output_section = & v850_elf_scom_section;
+         v850_elf_scom_section.symbol         = & v850_elf_scom_symbol;
+         v850_elf_scom_section.symbol_ptr_ptr = & v850_elf_scom_symbol_ptr;
+         v850_elf_scom_symbol.name            = ".scommon";
+         v850_elf_scom_symbol.flags           = BSF_SECTION_SYM;
+         v850_elf_scom_symbol.section         = & v850_elf_scom_section;
+         v850_elf_scom_symbol_ptr             = & v850_elf_scom_symbol;
+       }
+      asym->section = & v850_elf_scom_section;
+      asym->value = elfsym->internal_elf_sym.st_size;
+      break;
+      
+    case SHN_V850_TCOMMON:
+      if (v850_elf_tcom_section.name == NULL)
+       {
+         /* Initialize the tcommon section.  */
+         v850_elf_tcom_section.name           = ".tcommon";
+         v850_elf_tcom_section.flags          = SEC_IS_COMMON;
+         v850_elf_tcom_section.output_section = & v850_elf_tcom_section;
+         v850_elf_tcom_section.symbol         = & v850_elf_tcom_symbol;
+         v850_elf_tcom_section.symbol_ptr_ptr = & v850_elf_tcom_symbol_ptr;
+         v850_elf_tcom_symbol.name            = ".tcommon";
+         v850_elf_tcom_symbol.flags           = BSF_SECTION_SYM;
+         v850_elf_tcom_symbol.section         = & v850_elf_tcom_section;
+         v850_elf_tcom_symbol_ptr             = & v850_elf_tcom_symbol;
+       }
+      asym->section = & v850_elf_tcom_section;
+      asym->value = elfsym->internal_elf_sym.st_size;
+      break;
+
+    case SHN_V850_ZCOMMON:
+      if (v850_elf_zcom_section.name == NULL)
+       {
+         /* Initialize the zcommon section.  */
+         v850_elf_zcom_section.name           = ".zcommon";
+         v850_elf_zcom_section.flags          = SEC_IS_COMMON;
+         v850_elf_zcom_section.output_section = & v850_elf_zcom_section;
+         v850_elf_zcom_section.symbol         = & v850_elf_zcom_symbol;
+         v850_elf_zcom_section.symbol_ptr_ptr = & v850_elf_zcom_symbol_ptr;
+         v850_elf_zcom_symbol.name            = ".zcommon";
+         v850_elf_zcom_symbol.flags           = BSF_SECTION_SYM;
+         v850_elf_zcom_symbol.section         = & v850_elf_zcom_section;
+         v850_elf_zcom_symbol_ptr             = & v850_elf_zcom_symbol;
+       }
+      asym->section = & v850_elf_zcom_section;
+      asym->value = elfsym->internal_elf_sym.st_size;
+      break;
+    }
+}
+
+/* Hook called by the linker routine which adds symbols from an object
+   file.  We must handle the special MIPS section numbers here.  */
+
+/*ARGSUSED*/
+static boolean
+v850_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
+     bfd *                    abfd;
+     struct bfd_link_info *   info;
+     const Elf_Internal_Sym * sym;
+     const char **            namep;
+     flagword *               flagsp;
+     asection **              secp;
+     bfd_vma *                valp;
+{
+  switch (sym->st_shndx)
+    {
+    case SHN_V850_SCOMMON:
+      *secp = bfd_make_section_old_way (abfd, ".scommon");
+      (*secp)->flags |= SEC_IS_COMMON;
+      *valp = sym->st_size;
+      break;
+      
+    case SHN_V850_TCOMMON:
+      *secp = bfd_make_section_old_way (abfd, ".tcommon");
+      (*secp)->flags |= SEC_IS_COMMON;
+      *valp = sym->st_size;
+      break;
+      
+    case SHN_V850_ZCOMMON:
+      *secp = bfd_make_section_old_way (abfd, ".zcommon");
+      (*secp)->flags |= SEC_IS_COMMON;
+      *valp = sym->st_size;
+      break;
+    }
+
+  return true;
+}
+
+/*ARGSIGNORED*/
+static boolean
+v850_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec)
+     bfd *                  abfd;
+     struct bfd_link_info * info;
+     const char *           name;
+     Elf_Internal_Sym *     sym;
+     asection *             input_sec;
+{
+  /* If we see a common symbol, which implies a relocatable link, then
+     if a symbol was in a special common section in an input file, mark
+     it as a special common in the output file.  */
+  
+  if (sym->st_shndx == SHN_COMMON)
+    {
+      if (strcmp (input_sec->name, ".scommon") == 0)
+       sym->st_shndx = SHN_V850_SCOMMON;
+      else if (strcmp (input_sec->name, ".tcommon") == 0)
+       sym->st_shndx = SHN_V850_TCOMMON;
+      else if (strcmp (input_sec->name, ".zcommon") == 0)
+       sym->st_shndx = SHN_V850_ZCOMMON;
+    }
+
+  return true;
+}
+
+static boolean
+v850_elf_section_from_shdr (abfd, hdr, name)
+     bfd *               abfd;
+     Elf_Internal_Shdr * hdr;
+     char *              name;
+{
+  /* There ought to be a place to keep ELF backend specific flags, but
+     at the moment there isn't one.  We just keep track of the
+     sections by their name, instead.  */
+
+  if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name))
+    return false;
+
+  switch (hdr->sh_type)
+    {
+    case SHT_V850_SCOMMON:
+    case SHT_V850_TCOMMON:
+    case SHT_V850_ZCOMMON:
+      if (! bfd_set_section_flags (abfd, hdr->bfd_section,
+                                  (bfd_get_section_flags (abfd,
+                                                          hdr->bfd_section)
+                                   | SEC_IS_COMMON)))
+       return false;
+    }
+
+  return true;
+}
+
+/* Set the correct type for a V850 ELF section.  We do this by the
+   section name, which is a hack, but ought to work.  */
+static boolean
+v850_elf_fake_sections (abfd, hdr, sec)
+     bfd *                 abfd;
+     Elf32_Internal_Shdr * hdr;
+     asection *            sec;
+{
+  register const char * name;
+
+  name = bfd_get_section_name (abfd, sec);
+
+  if (strcmp (name, ".scommon") == 0)
+    {
+      hdr->sh_type = SHT_V850_SCOMMON;
+    }
+  else if (strcmp (name, ".tcommon") == 0)
+    {
+      hdr->sh_type = SHT_V850_TCOMMON;
+    }
+  else if (strcmp (name, ".zcommon") == 0)
+    hdr->sh_type = SHT_V850_ZCOMMON;
+  
+  return true;
+}
+
+
 \f
 #define TARGET_LITTLE_SYM                      bfd_elf32_v850_vec
 #define TARGET_LITTLE_NAME                     "elf32-v850"
@@ -1770,10 +2068,18 @@ v850_elf_print_private_bfd_data (abfd, ptr)
        
 #define elf_info_to_howto                      0
 #define elf_info_to_howto_rel                  v850_elf_info_to_howto_rel
+
 #define elf_backend_check_relocs               v850_elf_check_relocs
 #define elf_backend_relocate_section           v850_elf_relocate_section
 #define elf_backend_object_p                   v850_elf_object_p
 #define elf_backend_final_write_processing     v850_elf_final_write_processing
+#define elf_backend_section_from_bfd_section   v850_elf_section_from_bfd_section
+#define elf_backend_symbol_processing          v850_elf_symbol_processing
+#define elf_backend_add_symbol_hook            v850_elf_add_symbol_hook
+#define elf_backend_link_output_symbol_hook    v850_elf_link_output_symbol_hook
+#define elf_backend_section_from_shdr          v850_elf_section_from_shdr
+#define elf_backend_fake_sections              v850_elf_fake_sections
+
 #define bfd_elf32_bfd_is_local_label_name      v850_elf_is_local_label_name
 #define bfd_elf32_bfd_reloc_type_lookup                v850_elf_reloc_type_lookup
 #define bfd_elf32_bfd_copy_private_bfd_data    v850_elf_copy_private_bfd_data