Replaced fixed size array for hi16 relocations with a linked list.
[deliverable/binutils-gdb.git] / bfd / elf32-v850.c
index 7e4462185952297f59a1304fefb31cfbf4271b02..45b5f5d1d9b697cd2ed881694c362410961cf091 100644 (file)
@@ -37,20 +37,52 @@ 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
   PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
+static void v850_elf_info_to_howto_rela
+  PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
 static bfd_reloc_status_type v850_elf_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static boolean v850_elf_is_local_label_name PARAMS ((bfd *, const char *));
-static boolean v850_elf_relocate_section PARAMS((bfd *,
-                                                struct bfd_link_info *,
-                                                bfd *,
-                                                asection *,
-                                                bfd_byte *,
-                                                Elf_Internal_Rela *,
-                                                Elf_Internal_Sym *,
-                                                asection **));
-/* Try to minimize the amount of space occupied by relocation tables
-   on the ROM (not that the ROM won't be swamped by other ELF overhead).  */
-#define USE_REL
+static boolean v850_elf_is_local_label_name
+  PARAMS ((bfd *, const char *));
+static boolean v850_elf_relocate_section
+  PARAMS((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+         Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
+static bfd_reloc_status_type v850_elf_perform_relocation
+  PARAMS ((bfd *, int, bfd_vma, bfd_byte *));
+static boolean v850_elf_check_relocs
+  PARAMS ((bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *));
+static void remember_hi16s_reloc
+  PARAMS ((bfd *, bfd_vma, bfd_byte *));
+static bfd_byte * find_remembered_hi16s_reloc
+  PARAMS ((bfd_vma addend));
+static bfd_reloc_status_type v850_elf_final_link_relocate
+  PARAMS ((reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *, bfd_vma,
+          bfd_vma, bfd_vma, struct bfd_link_info *, asection *, int));
+static boolean v850_elf_object_p
+  PARAMS ((bfd *));
+static boolean v850_elf_fake_sections
+  PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *));
+static void v850_elf_final_write_processing
+  PARAMS ((bfd *, boolean));
+static boolean v850_elf_set_private_flags
+  PARAMS ((bfd *, flagword));
+static boolean v850_elf_copy_private_bfd_data
+  PARAMS ((bfd *, bfd *));
+static boolean v850_elf_merge_private_bfd_data
+  PARAMS ((bfd *, bfd *));
+static boolean v850_elf_print_private_bfd_data
+  PARAMS ((bfd *, PTR));
+static boolean v850_elf_section_from_bfd_section
+  PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *, int *));
+static void v850_elf_symbol_processing
+  PARAMS ((bfd *, asymbol *));
+static boolean v850_elf_add_symbol_hook
+  PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
+          const char **, flagword *, asection **, bfd_vma *));
+static boolean v850_elf_link_output_symbol_hook
+  PARAMS ((bfd *, struct bfd_link_info *, const char *,
+          Elf_Internal_Sym *, asection *));
+static boolean v850_elf_section_from_shdr
+  PARAMS ((bfd *, Elf_Internal_Shdr *, char *));
 
 /* Note: It is REQUIRED that the 'type' value of each entry in this array
    match the index of the entry in the array.  */
@@ -404,6 +436,36 @@ static reloc_howto_type v850_elf_howto_table[] =
         false),                        /* pcrel_offset */
 
 /* end-sanitize-v850e */
+  /* GNU extension to record C++ vtable hierarchy */
+  HOWTO (R_V850_GNU_VTINHERIT, /* type */
+         0,                     /* rightshift */
+         2,                     /* size (0 = byte, 1 = short, 2 = long) */
+         0,                     /* bitsize */
+         false,                 /* pc_relative */
+         0,                     /* bitpos */
+         complain_overflow_dont, /* complain_on_overflow */
+         NULL,                  /* special_function */
+         "R_V850_GNU_VTINHERIT", /* name */
+         false,                 /* partial_inplace */
+         0,                     /* src_mask */
+         0,                     /* dst_mask */
+         false),                /* pcrel_offset */
+
+  /* GNU extension to record C++ vtable member usage */
+  HOWTO (R_V850_GNU_VTENTRY,     /* type */
+         0,                     /* rightshift */
+         2,                     /* size (0 = byte, 1 = short, 2 = long) */
+         0,                     /* bitsize */
+         false,                 /* pc_relative */
+         0,                     /* bitpos */
+         complain_overflow_dont, /* complain_on_overflow */
+         _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
+         "R_V850_GNU_VTENTRY",   /* name */
+         false,                 /* partial_inplace */
+         0,                     /* src_mask */
+         0,                     /* dst_mask */
+         false),                /* pcrel_offset */
 };
 
 /* Map BFD reloc types to V850 ELF reloc types.  */
@@ -441,6 +503,9 @@ static const struct v850_elf_reloc_map v850_elf_reloc_map[] =
   { BFD_RELOC_V850_CALLT_6_7_OFFSET,       R_V850_CALLT_6_7_OFFSET       },
   { BFD_RELOC_V850_CALLT_16_16_OFFSET,     R_V850_CALLT_16_16_OFFSET     },
 /* end-sanitize-v850e */
+  { BFD_RELOC_VTABLE_INHERIT,               R_V850_GNU_VTINHERIT },
+  { BFD_RELOC_VTABLE_ENTRY,                 R_V850_GNU_VTENTRY },
+
 };
 
 \f
@@ -482,6 +547,20 @@ v850_elf_info_to_howto_rel (abfd, cache_ptr, dst)
   cache_ptr->howto = &v850_elf_howto_table[r_type];
 }
 
+/* Set the howto pointer for a V850 ELF reloc (type RELA). */
+static void
+v850_elf_info_to_howto_rela (abfd, cache_ptr, dst)
+     bfd *                 abfd;
+     arelent *             cache_ptr;
+     Elf32_Internal_Rela   *dst;
+{
+  unsigned int r_type;
+
+  r_type = ELF32_R_TYPE (dst->r_info);
+  BFD_ASSERT (r_type < (unsigned int) R_V850_max);
+  cache_ptr->howto = &v850_elf_howto_table[r_type];
+}
+
 \f
 /* Look through the relocs for a section during the first phase, and
    allocate space in the global offset table or procedure linkage
@@ -550,6 +629,20 @@ v850_elf_check_relocs (abfd, info, sec, relocs)
 /* end-sanitize-v850e */
          break;
 
+        /* This relocation describes the C++ object vtable hierarchy.
+           Reconstruct it for later use during GC.  */
+        case R_V850_GNU_VTINHERIT:
+          if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+            return false;
+          break;
+
+        /* This relocation describes which C++ vtable entries are actually
+           used.  Record for later use during GC.  */
+        case R_V850_GNU_VTENTRY:
+          if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+            return false;
+          break;
+
 /* start-sanitize-v850e */
        case R_V850_SDA_16_16_SPLIT_OFFSET:
 /* end-sanitize-v850e */
@@ -590,28 +683,28 @@ v850_elf_check_relocs (abfd, info, sec, relocs)
                  && (h->other & V850_OTHER_ERROR) == 0)
                {
                  const char * msg;
-                 static char  buff[100]; /* XXX */
-                 
+                 static char  buff[200]; /* XXX */
+
                  switch (h->other & V850_OTHER_MASK)
                    {
                    default:
-                     msg = "cannot occupy in multiple small data regions";
+                     msg = _("Variable `%s' cannot occupy in multiple small data regions");
                      break;
                    case V850_OTHER_SDA | V850_OTHER_ZDA | V850_OTHER_TDA:
-                     msg = "can only be in one of the small, zero, and tiny data regions";
+                     msg = _("Variable `%s' can only be in one of the small, zero, and tiny data regions");
                      break;
                    case V850_OTHER_SDA | V850_OTHER_ZDA:
-                     msg = "cannot be in both small and zero data regions simultaneously";
+                     msg = _("Variable `%s' cannot be in both small and zero data regions simultaneously");
                      break;
                    case V850_OTHER_SDA | V850_OTHER_TDA:
-                     msg = "cannot be in both small and tiny data regions simultaneously";
+                     msg = _("Variable `%s' cannot be in both small and tiny data regions simultaneously");
                      break;
                    case V850_OTHER_ZDA | V850_OTHER_TDA:
-                     msg = "cannot be in both zero and tiny data regions simultaneously";
+                     msg = _("Variable `%s' cannot be in both zero and tiny data regions simultaneously");
                      break;
                    }
 
-                 sprintf (buff, "Variable '%s' %s", h->root.root.string, msg );
+                 sprintf (buff, msg, h->root.root.string);
                  info->callbacks->warning (info, buff, h->root.root.string,
                                            abfd, h->root.u.def.section, 0);
 
@@ -642,17 +735,111 @@ v850_elf_check_relocs (abfd, info, sec, relocs)
   return ret;
 }
 
+typedef struct hi16s_location
+{
+  bfd_vma       addend;
+  bfd_byte *    address;
+  unsigned long counter;
+  struct hi16s_location * next;
+}
+hi16s_location;
+
+static hi16s_location *  previous_hi16s;
+static hi16s_location *  free_hi16s;
+static unsigned long     hi16s_counter;
+
+static void
+remember_hi16s_reloc (abfd, addend, address)
+     bfd *      abfd;
+     bfd_vma    addend;
+     bfd_byte * address;
+{
+  hi16s_location * entry = NULL;
+  
+  /* Find a free structure.  */
+  if (free_hi16s == NULL)
+    free_hi16s = (hi16s_location *) bfd_zalloc (abfd, sizeof (* free_hi16s));
+
+  entry = free_hi16s;
+  free_hi16s = free_hi16s->next;
+  
+  entry->addend  = addend;
+  entry->address = address;
+  entry->counter = hi16s_counter ++;
+  entry->next    = previous_hi16s;
+  previous_hi16s = entry;
+  
+  /* Cope with wrap around of our counter.  */
+  if (hi16s_counter == 0)
+    {
+      /* XXX - Assume that all counter entries differ only in their low 16 bits.  */
+      for (entry = previous_hi16s; entry != NULL; entry = entry->next)
+       entry->counter &= 0xffff;
+
+      hi16s_counter = 0x10000;
+    }
+  
+  return;
+}
+
+static bfd_byte *
+find_remembered_hi16s_reloc (addend)
+     bfd_vma addend;
+{
+  hi16s_location * match = NULL;
+  hi16s_location * entry;
+  hi16s_location * previous = NULL;
+  hi16s_location * prev;
+  int              i;
+  bfd_byte *       addr;
+  
+  /* Search the table.  Record the most recent entry that matches.  */
+  for (entry = previous_hi16s; entry; entry = entry->next)
+    {
+      if (entry->addend == addend)
+       {
+         if (match == NULL || match->counter < entry->counter)
+           {
+             previous = prev;
+             match    = entry;
+           }
+       }
+         
+      prev = entry;
+    }
+
+  if (match == NULL)
+    return NULL;
+
+  /* Extract the address.  */
+  addr = match->address;
+  
+  /* Attach the entry to the free list.  */
+  if (previous)
+    previous->next = match->next;
+  else
+    previous_hi16s = match->next;
+  
+  match->next = free_hi16s->next;
+  free_hi16s  = match;
+  
+  match->addend  = 0;
+  match->address = NULL;
+  
+  return addr;
+}     
+
+/* FIXME:  The code here probably ought to be removed and the code in reloc.c
+   allowed to do its  stuff instead.  At least for most of the relocs, anwyay.  */
 static bfd_reloc_status_type
-v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
+v850_elf_perform_relocation (abfd, r_type, addend, address)
      bfd *      abfd;
      int        r_type;
-     long       addend;
+     bfd_vma    addend;
      bfd_byte * address;
-     boolean    replace;
 {
-  static long       last_hi16s_addend;
-  static bfd_byte * last_hi16s_address;
   unsigned long insn;
+  bfd_signed_vma saddend = (bfd_signed_vma) addend;
   
   switch (r_type)
     {
@@ -661,14 +848,11 @@ v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
       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 (addend > 0x1fffff || addend < -0x200000)
+      if (saddend > 0x1fffff || saddend < -0x200000)
        return bfd_reloc_overflow;
       
       if ((addend % 2) != 0)
@@ -681,7 +865,7 @@ v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
       return bfd_reloc_ok;
       
     case R_V850_9_PCREL:
-      if (addend > 0xff || addend < -0x100)
+      if (saddend > 0xff || saddend < -0x100)
        return bfd_reloc_overflow;
       
       if ((addend % 2) != 0)
@@ -692,160 +876,209 @@ v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
       insn |= ((addend & 0x1f0) << 7) | ((addend & 0x0e) << 3);
       break;
       
-    case R_V850_HI16_S:
-      last_hi16s_addend = addend;
-      last_hi16s_address = address;
+    case R_V850_HI16:
+      addend += (bfd_get_16 (abfd, address) << 16);
+      addend = (addend >> 16);
+      insn = addend;
+      break;
       
+    case R_V850_HI16_S:
+      /* Remember where this relocation took place.  */
+      remember_hi16s_reloc (abfd, addend, address);
+
       addend += (bfd_get_16 (abfd, address) << 16);
       addend = (addend >> 16) + ((addend & 0x8000) != 0);
+      
       /* This relocation cannot overflow. */
-      if (addend > 0x7fff || addend < -0x8000)
+      if (addend > 0x7fff)
        addend = 0;
-      insn = addend;
-      break;
       
-    case R_V850_HI16:
-      addend += (bfd_get_16 (abfd, address) << 16);
-      addend = (addend >> 16);
       insn = addend;
       break;
       
     case R_V850_LO16:
       /* Calculate the sum of the value stored in the instruction and the
         addend and check for overflow from the low 16 bits into the high
-        16 bits.  This can occur if the computation sets the 16th bit when
-        before it was clear, since the 16th bit will be sign extended into
-        the high part, thus reducing its value by one, but since the 16th bit
-        was originally clear, the previous R_V850_HI16_S relocation will not
-        have added in an additional 1 to the high part to compensate for this
-        effect.  Overflow can also occur if the compuation carries into the
-        17th bit and it also results in the 16th bit having the same value as
-        the 16th bit of the original value.   What happens is that the
-        R_V850_HI16_S relocation will have already examined the 16th bit of
-        the original value and added 1 to the high part if the bit is set.
-        This compensates for the sign extension of 16th bit of the result of
-        the computation.  But now there is a carry into the 17th bit, and this
-        has not been allowed for.  Note - there is no need to change anything
-        if a carry occurs, and the 16th bit changes its value, (this can only
-        happen if the bit was set in the original value, but is clear in the
-        result of the computation), as the R_V850_HI16_S relocation will have
-        already added in 1 to the high part for us.  Here are some examples:
-
-        original value = 0x12345
-        addend         = 0x01234
-                         -------
-                         0x13579  => R_V850_HI16_S stores 0x0001
-                                     R_V850_LO16   stores 0x3579
-                                                   
-                                     This is OK.
-
-        original value = 0x12345
-        addend         = 0x07000
-                         -------
-                         0x19345  => R_V850_HI16_S stores 0x0001
-                                     R_V850_LO16   stores 0x9345
-
-                                     but the 0x9345 value gets sign
-                                     extended, so the sum becomes:
-
-                                     0x00010000
-                                     0xffff9345
-                                     ----------
-                                     0x00009345  which is wrong.
-
-                                     This is the first example of overflow.
-
-         original value = 0x18888
-         addend         = 0x08888
-                          -------
-                          0x21110 => R_V850_HI16_S stores 0x0002 (because 16th bit of the original value is set)
-                                     R_V850_LO16   stores 0x1110
-
-                                     and the sum is now:
-
-                                     0x00020000
-                                     0x00001110
-                                     ----------
-                                     0x00021110 which is OK.
-
-         original value = 0x1ffff
-         addend         = 0x08888
-                          -------
-                          0x28887 => R_V850_HI16_S stores 0x0002
-                                     R_V850_LO16   stores 0x8887
-
-                                     and the sum is now:
-
-                                     0x00020000
-                                     0xffff8887
-                                     ----------
-                                     0x00018887 which is wrong.
-
-                                     This is the second example of overflow.
-                                     (The 16th bit remains set).
-
-          original value = 0x15555
-          addend         = 0x0ffff
-                           -------
-                           0x25554 => R_V850_HI16_S stores 0x0001
-                                      R_V850_LO16   stores 0x5554
-
-                                      the sum is now:
-
-                                      0x00010000
-                                      0x00005554
-                                      ----------
-                                      0x00015554 which is wrong.
-
-                                      This is the other form of the second
-                                      example of overflow.  (The 16th bit
-                                      remains clear)
+        16 bits.  The assembler has already done some of this:  If the
+        value stored in the instruction has its 15th bit set, (counting
+        from zero) then the assembler will have added 1 to the value
+        stored in the associated HI16S reloc.  So for example, these
+        relocations:
+
+            movhi hi( fred ), r0, r1
+            movea lo( fred ), r1, r1
+
+        will store 0 in the value fields for the MOVHI and MOVEA instructions
+        and addend will be the address of fred, but for these instructions:
+
+            movhi hi( fred + 0x123456), r0, r1
+            movea lo( fred + 0x123456), r1, r1
+
+        the value stored in the MOVHI instruction will be 0x12 and the value
+        stored in the MOVEA instruction will be 0x3456.  If however the
+        instructions were:
+
+            movhi hi( fred + 0x10ffff), r0, r1
+            movea lo( fred + 0x10ffff), r1, r1
+
+        then the value stored in the MOVHI instruction would be 0x11 (not
+        0x10) and the value stored in the MOVEA instruction would be 0xffff.
+        Thus (assuming for the moment that the addend is 0), at run time the
+        MOVHI instruction loads 0x110000 into r1, then the MOVEA instruction
+        adds 0xffffffff (sign extension!) producing 0x10ffff.  Similarly if
+        the instructions were:
+
+            movhi hi( fred - 1), r0, r1
+            movea lo( fred - 1), r1, r1
+
+        then 0 is stored in the MOVHI instruction and -1 is stored in the
+        MOVEA instruction.
+
+        Overflow can occur if the addition of the value stored in the
+        instruction plus the addend sets the 15th bit when before it was clear.
+        This is because the 15th bit will be sign extended into the high part,
+        thus reducing its value by one, but since the 15th bit was originally
+        clear, the assembler will not have added 1 to the previous HI16S reloc
+        to compensate for this effect.  For example:
+
+           movhi hi( fred + 0x123456), r0, r1
+           movea lo( fred + 0x123456), r1, r1
+
+        The value stored in HI16S reloc is 0x12, the value stored in the LO16
+        reloc is 0x3456.  If we assume that the address of fred is 0x00007000
+        then the relocations become:
+
+          HI16S: 0x0012 + (0x00007000 >> 16)    = 0x12
+          LO16:  0x3456 + (0x00007000 & 0xffff) = 0xa456
+
+        but when the instructions are executed, the MOVEA instruction's value
+        is signed extended, so the sum becomes:
+
+             0x00120000
+           + 0xffffa456
+           ------------
+             0x0011a456    but 'fred + 0x123456' = 0x0012a456
+
+        Note that if the 15th bit was set in the value stored in the LO16
+        reloc, then we do not have to do anything:
+
+           movhi hi( fred + 0x10ffff), r0, r1
+           movea lo( fred + 0x10ffff), r1, r1
+
+           HI16S:  0x0011 + (0x00007000 >> 16)    = 0x11
+           LO16:   0xffff + (0x00007000 & 0xffff) = 0x6fff
+
+             0x00110000
+           + 0x00006fff
+           ------------
+             0x00116fff  = fred + 0x10ffff = 0x7000 + 0x10ffff
+
+        
+        Overflow can also occur if the computation carries into the 16th bit
+        and it also results in the 15th bit having the same value as the 15th
+        bit of the original value.   What happens is that the HI16S reloc
+        will have already examined the 15th bit of the original value and
+        added 1 to the high part if the bit is set.  This compensates for the
+        sign extension of 15th bit of the result of the computation.  But now
+        there is a carry into the 16th bit, and this has not been allowed for.
+
+        So, for example if fred is at address 0xf000:
+
+          movhi hi( fred + 0xffff), r0, r1    [bit 15 of the offset is set]
+          movea lo( fred + 0xffff), r1, r1
+
+          HI16S: 0x0001 + (0x0000f000 >> 16)    = 0x0001
+          LO16:  0xffff + (0x0000f000 & 0xffff) = 0xefff   (carry into bit 16 is lost)
+
+            0x00010000
+          + 0xffffefff
+          ------------
+            0x0000efff   but 'fred + 0xffff' = 0x0001efff
+
+        Similarly, if the 15th bit remains clear, but overflow occurs into
+        the 16th bit then (assuming the address of fred is 0xf000):
+
+          movhi hi( fred + 0x7000), r0, r1    [bit 15 of the offset is clear]
+          movea lo( fred + 0x7000), r1, r1
+
+          HI16S: 0x0000 + (0x0000f000 >> 16)    = 0x0000
+          LO16:  0x7000 + (0x0000f000 & 0xffff) = 0x6fff  (carry into bit 16 is lost)
+
+            0x00000000
+          + 0x00006fff
+          ------------
+            0x00006fff   but 'fred + 0x7000' = 0x00016fff
+          
+        Note - there is no need to change anything if a carry occurs, and the
+        15th bit changes its value from being set to being clear, as the HI16S
+        reloc will have already added in 1 to the high part for us:
+
+          movhi hi( fred + 0xffff), r0, r1     [bit 15 of the offset is set]
+          movea lo( fred + 0xffff), r1, r1
+
+          HI16S: 0x0001 + (0x00007000 >> 16)
+          LO16:  0xffff + (0x00007000 & 0xffff) = 0x6fff  (carry into bit 16 is lost)
+
+            0x00010000
+          + 0x00006fff   (bit 15 not set, so the top half is zero)
+          ------------
+            0x00016fff   which is right (assuming that fred is at 0x7000)
+
+        but if the 15th bit goes from being clear to being set, then we must
+        once again handle overflow:
+
+          movhi hi( fred + 0x7000), r0, r1     [bit 15 of the offset is clear]
+          movea lo( fred + 0x7000), r1, r1
+
+          HI16S: 0x0000 + (0x0000ffff >> 16)
+          LO16:  0x7000 + (0x0000ffff & 0xffff) = 0x6fff  (carry into bit 16)
+
+            0x00000000
+          + 0x00006fff   (bit 15 not set, so the top half is zero)
+          ------------
+            0x00006fff   which is wrong (assuming that fred is at 0xffff)
         */
 
       {
        long result;
-       
+
        insn   = bfd_get_16 (abfd, address);
        result = insn + addend;
 
-#define BIT16_SET(x) ((x) & 0x8000)
-#define OVERFLOWS(a,i) (((a) & 0xffff) + (i) > 0xffff)
+#define BIT15_SET(x) ((x) & 0x8000)
+#define OVERFLOWS(a,i) ((((a) & 0xffff) + (i)) > 0xffff)
        
-       if ((BIT16_SET (result) && ! BIT16_SET (addend))
-           || (OVERFLOWS (addend, insn) 
-               && (BIT16_SET (result) == BIT16_SET (addend))))
+       if ((BIT15_SET (result) && ! BIT15_SET (addend))
+           || (OVERFLOWS (addend, insn)
+               && ((! BIT15_SET (insn)) || (BIT15_SET (addend)))))
          {
-           /* Amend the preceding HI16_S relocation, allowing for
-              an intervening instruction, which does occasionally happen.  */
-           if (   (addend  == last_hi16s_addend)
-               && (   (address == last_hi16s_address + 4)
-                   || (address == last_hi16s_address + 8)))
+           bfd_byte * hi16s_address = find_remembered_hi16s_reloc (addend);
+           
+           /* Amend the matching HI16_S relocation.  */
+           if (hi16s_address != NULL)
              {
-               insn = bfd_get_16 (abfd, last_hi16s_address);
+               insn = bfd_get_16 (abfd, hi16s_address);
                insn += 1;
-               bfd_put_16 (abfd, insn, last_hi16s_address);
+               bfd_put_16 (abfd, insn, hi16s_address);
              }
            else
              {
-               fprintf (stderr, "FAILED to find previous HI16 reloc:\n");
-               fprintf (stderr, "addend = %x, last_hi16s_added = %x, address = %x, last_address = %x\n",
-                        addend, last_hi16s_addend, address, last_hi16s_address);
-               fprintf (stderr, "addend = %x, result = %x, insn = %x\n",
-                        addend, result, insn);
+               fprintf (stderr, _("FAILED to find previous HI16 reloc\n"));
                return bfd_reloc_overflow;
              }
          }
        
        /* Do not complain if value has top bit set, as this has been anticipated.  */
        insn = result & 0xffff;
+       break;
       }
-    break;
 
     case R_V850_8:
-      if (! replace)
-       addend += (char) bfd_get_8 (abfd, address);
+      addend += (char) bfd_get_8 (abfd, address);
 
-      if (addend > 0x7f || addend < -0x80)
+      saddend = (bfd_signed_vma) addend;
+      
+      if (saddend > 0x7f || saddend < -0x80)
        return bfd_reloc_overflow;
 
       bfd_put_8 (abfd, addend, address);
@@ -853,10 +1086,11 @@ v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
 
 /* start-sanitize-v850e */
     case R_V850_CALLT_16_16_OFFSET:
-      if (! replace)
-       addend += bfd_get_16 (abfd, address);
+      addend += bfd_get_16 (abfd, address);
+      
+      saddend = (bfd_signed_vma) addend;
       
-      if (addend > 0xffff || addend < 0)
+      if (saddend > 0xffff || saddend < 0)
        return bfd_reloc_overflow;
 
       insn = addend;
@@ -864,15 +1098,16 @@ v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
 /* end-sanitize-v850e */
       
     case R_V850_16:
-      replace = false;
+
       /* drop through */            
     case R_V850_SDA_16_16_OFFSET:
     case R_V850_ZDA_16_16_OFFSET:
     case R_V850_TDA_16_16_OFFSET:
-      if (! replace)
-       addend += bfd_get_16 (abfd, address);
+      addend += bfd_get_16 (abfd, address);
       
-      if (addend > 0x7fff || addend < -0x8000)
+      saddend = (bfd_signed_vma) addend;
+      
+      if (saddend > 0x7fff || saddend < -0x8000)
        return bfd_reloc_overflow;
 
       insn = addend;
@@ -881,26 +1116,26 @@ v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
     case R_V850_SDA_15_16_OFFSET:
     case R_V850_ZDA_15_16_OFFSET:
       insn = bfd_get_16 (abfd, address);
-
-      if (! replace)
-       addend += (insn & 0xfffe);
+      addend += (insn & 0xfffe);
+      
+      saddend = (bfd_signed_vma) addend;
       
-      if (addend > 0x7ffe || addend < -0x8000)
+      if (saddend > 0x7ffe || saddend < -0x8000)
        return bfd_reloc_overflow;
       
       if (addend & 1)
-       return bfd_reloc_dangerous;
+        return bfd_reloc_dangerous;
       
       insn = (addend & ~1) | (insn & 1);
       break;
       
     case R_V850_TDA_6_8_OFFSET:
       insn = bfd_get_16 (abfd, address);
-
-      if (! replace)
-       addend += ((insn & 0x7e) << 1);
+      addend += ((insn & 0x7e) << 1);
+      
+      saddend = (bfd_signed_vma) addend;
       
-      if (addend > 0xfc || addend < 0)
+      if (saddend > 0xfc || saddend < 0)
        return bfd_reloc_overflow;
       
       if (addend & 3)
@@ -912,11 +1147,11 @@ v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
       
     case R_V850_TDA_7_8_OFFSET:
       insn = bfd_get_16 (abfd, address);
-
-      if (! replace)
-       addend += ((insn & 0x7f) << 1);
+      addend += ((insn & 0x7f) << 1);
+      
+      saddend = (bfd_signed_vma) addend;
       
-      if (addend > 0xfe || addend < 0)
+      if (saddend > 0xfe || saddend < 0)
        return bfd_reloc_overflow;
       
       if (addend & 1)
@@ -928,11 +1163,11 @@ v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
       
     case R_V850_TDA_7_7_OFFSET:
       insn = bfd_get_16 (abfd, address);
-
-      if (! replace)
-       addend += insn & 0x7f;
+      addend += insn & 0x7f;
        
-      if (addend > 0x7f || addend < 0)
+      saddend = (bfd_signed_vma) addend;
+      
+      if (saddend > 0x7f || saddend < 0)
        return bfd_reloc_overflow;
       
       insn &= 0xff80;
@@ -942,11 +1177,11 @@ v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
 /* start-sanitize-v850e */
     case R_V850_TDA_4_5_OFFSET:
       insn = bfd_get_16 (abfd, address);
-
-      if (! replace)
-       addend += ((insn & 0xf) << 1);
+      addend += ((insn & 0xf) << 1);
       
-      if (addend > 0x1e || addend < 0)
+      saddend = (bfd_signed_vma) addend;
+      
+      if (saddend > 0x1e || saddend < 0)
        return bfd_reloc_overflow;
       
       if (addend & 1)
@@ -958,11 +1193,11 @@ v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
       
     case R_V850_TDA_4_4_OFFSET:
       insn = bfd_get_16 (abfd, address);
-
-      if (! replace)
-       addend += insn & 0xf;
+      addend += insn & 0xf;
+      
+      saddend = (bfd_signed_vma) addend;
       
-      if (addend > 0xf || addend < 0)
+      if (saddend > 0xf || saddend < 0)
        return bfd_reloc_overflow;
       
       insn &= 0xfff0;
@@ -972,11 +1207,11 @@ v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
     case R_V850_ZDA_16_16_SPLIT_OFFSET:
     case R_V850_SDA_16_16_SPLIT_OFFSET:
       insn = bfd_get_32 (abfd, address);
-
-      if (! replace)
-       addend += ((insn & 0xfffe0000) >> 16) + ((insn & 0x20) >> 5);
+      addend += ((insn & 0xfffe0000) >> 16) + ((insn & 0x20) >> 5);
+      
+      saddend = (bfd_signed_vma) addend;
       
-      if (addend > 0x7fff || addend < -0x8000)
+      if (saddend > 0x7fff || saddend < -0x8000)
        return bfd_reloc_overflow;
       
       insn &= 0x0001ffdf;
@@ -988,11 +1223,11 @@ v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
       
     case R_V850_CALLT_6_7_OFFSET:
       insn = bfd_get_16 (abfd, address);
-
-      if (! replace)
-        addend += ((insn & 0x3f) << 1);
+      addend += ((insn & 0x3f) << 1);
       
-      if (addend > 0x7e || addend < 0)
+      saddend = (bfd_signed_vma) addend;
+      
+      if (saddend > 0x7e || saddend < 0)
        return bfd_reloc_overflow;
       
       if (addend & 1)
@@ -1002,6 +1237,11 @@ v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
       insn |= (addend >> 1);
       break;
 /* end-sanitize-v850e */
+
+    case R_V850_GNU_VTINHERIT:
+    case R_V850_GNU_VTENTRY:
+      return bfd_reloc_ok;
+
     }
 
   bfd_put_16 (abfd, insn, address);
@@ -1021,8 +1261,6 @@ v850_elf_reloc (abfd, reloc, symbol, data, isection, obfd, err)
      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),
@@ -1080,11 +1318,8 @@ v850_elf_reloc (abfd, reloc, symbol, data, isection, obfd, err)
       relocation -= reloc->address;
     }
 
-  /* 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);
+  reloc->addend = relocation;  
+  return bfd_reloc_ok;
 }
 
 \f
@@ -1252,6 +1487,8 @@ v850_elf_final_link_relocate (howto, input_bfd, output_bfd,
 /* end-sanitize-v850e */
       
     case R_V850_NONE:
+    case R_V850_GNU_VTINHERIT:
+    case R_V850_GNU_VTENTRY:
       return bfd_reloc_ok;
 
     default:
@@ -1259,7 +1496,7 @@ v850_elf_final_link_relocate (howto, input_bfd, output_bfd,
     }
 
   /* Perform the relocation.  */
-  return v850_elf_store_addend_in_insn (input_bfd, r_type, value, hit_data, false);
+  return v850_elf_perform_relocation (input_bfd, r_type, value + addend, hit_data); 
 }
 
 \f
@@ -1299,6 +1536,11 @@ v850_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type   = ELF32_R_TYPE (rel->r_info);
+
+      if (r_type == R_V850_GNU_VTENTRY
+          || r_type == R_V850_GNU_VTINHERIT)
+        continue;
+
       howto    = v850_elf_howto_table + r_type;
 
       if (info->relocateable)
@@ -1313,29 +1555,7 @@ 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
                }
            }
 
@@ -1445,31 +1665,31 @@ fprintf (stderr, "unknown: name: %s\n", h->root.root.string);
              break;
 
            case bfd_reloc_outofrange:
-             msg = "internal error: out of range error";
+             msg = _("internal error: out of range error");
              goto common_error;
 
            case bfd_reloc_notsupported:
-             msg = "internal error: unsupported relocation error";
+             msg = _("internal error: unsupported relocation error");
              goto common_error;
 
            case bfd_reloc_dangerous:
-             msg = "internal error: dangerous relocation";
+             msg = _("internal error: dangerous relocation");
              goto common_error;
 
            case bfd_reloc_other:
-             msg = "could not locate special linker symbol __gp";
+             msg = _("could not locate special linker symbol __gp");
              goto common_error;
 
            case bfd_reloc_continue:
-             msg = "could not locate special linker symbol __ep";
+             msg = _("could not locate special linker symbol __ep");
              goto common_error;
 
            case (bfd_reloc_dangerous + 1):
-             msg = "could not locate special linker symbol __ctbp";
+             msg = _("could not locate special linker symbol __ctbp");
              goto common_error;
              
            default:
-             msg = "internal error: unknown error";
+             msg = _("internal error: unknown error");
              /* fall through */
 
            common_error:
@@ -1485,6 +1705,57 @@ fprintf (stderr, "unknown: name: %s\n", h->root.root.string);
   return true;
 }
 
+static boolean
+v850_elf_gc_sweep_hook (abfd, info, sec, relocs)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     const Elf_Internal_Rela *relocs;
+{
+  /* No got and plt entries for v850-elf */
+  return true;
+}
+
+static asection *
+v850_elf_gc_mark_hook (abfd, info, rel, h, sym)
+       bfd *abfd;
+       struct bfd_link_info *info;
+       Elf_Internal_Rela *rel;
+       struct elf_link_hash_entry *h;
+       Elf_Internal_Sym *sym;
+{
+  if (h != NULL)
+    {
+      switch (ELF32_R_TYPE (rel->r_info))
+      {
+      case R_V850_GNU_VTINHERIT:
+      case R_V850_GNU_VTENTRY:
+        break;
+
+      default:
+        switch (h->root.type)
+          {
+          case bfd_link_hash_defined:
+          case bfd_link_hash_defweak:
+            return h->root.u.def.section;
+
+          case bfd_link_hash_common:
+            return h->root.u.c.p->section;
+          }
+       }
+     }
+   else
+     {
+       if (!(elf_bad_symtab (abfd)
+           && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
+         && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
+                && sym->st_shndx != SHN_COMMON))
+          {
+            return bfd_section_from_elf_index (abfd, sym->st_shndx);
+          }
+      }
+  return NULL;
+}
 /* Set the right machine number.  */
 static boolean
 v850_elf_object_p (abfd)
@@ -1499,10 +1770,11 @@ v850_elf_object_p (abfd)
     case E_V850EA_ARCH: (void) bfd_default_set_arch_mach (abfd, bfd_arch_v850, bfd_mach_v850ea); break;
 /* end-sanitize-v850e */
     }
+  return true;
 }
 
 /* Store the machine number in the flags field.  */
-void
+static void
 v850_elf_final_write_processing (abfd, linker)
      bfd *   abfd;
      boolean linker;
@@ -1524,7 +1796,7 @@ v850_elf_final_write_processing (abfd, linker)
 }
 
 /* Function to keep V850 specific file flags. */
-boolean
+static boolean
 v850_elf_set_private_flags (abfd, flags)
      bfd *    abfd;
      flagword flags;
@@ -1538,7 +1810,7 @@ v850_elf_set_private_flags (abfd, flags)
 }
 
 /* Copy backend specific data from one object module to another */
-boolean
+static boolean
 v850_elf_copy_private_bfd_data (ibfd, obfd)
      bfd * ibfd;
      bfd * obfd;
@@ -1559,7 +1831,7 @@ v850_elf_copy_private_bfd_data (ibfd, obfd)
 
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
-boolean
+static boolean
 v850_elf_merge_private_bfd_data (ibfd, obfd)
      bfd * ibfd;
      bfd * obfd;
@@ -1603,7 +1875,7 @@ v850_elf_merge_private_bfd_data (ibfd, obfd)
 
   if ((in_flags & EF_V850_ARCH) != (out_flags & EF_V850_ARCH)
       && (in_flags & EF_V850_ARCH) != E_V850_ARCH)
-    _bfd_error_handler ("%s: Architecture mismatch with previous modules",
+    _bfd_error_handler (_("%s: Architecture mismatch with previous modules"),
                        bfd_get_filename (ibfd));
 
   return true;
@@ -1617,17 +1889,20 @@ v850_elf_print_private_bfd_data (abfd, ptr)
 {
   FILE * file = (FILE *) ptr;
   
-  BFD_ASSERT (abfd != NULL && ptr != NULL)
+  BFD_ASSERT (abfd != NULL && ptr != NULL);
+  
+  _bfd_elf_print_private_bfd_data (abfd, ptr);
   
-  fprintf (file, "private flags = %x", elf_elfheader (abfd)->e_flags);
+  /* xgettext:c-format */
+  fprintf (file, _("private flags = %lx: "), elf_elfheader (abfd)->e_flags);
   
   switch (elf_elfheader (abfd)->e_flags & EF_V850_ARCH)
     {
     default:
-    case E_V850_ARCH: fprintf (file, ": v850 architecture"); break;
+    case E_V850_ARCH: fprintf (file, _("v850 architecture")); break;
 /* start-sanitize-v850e */
-    case E_V850E_ARCH:  fprintf (file, ": v850e architecture"); break;
-    case E_V850EA_ARCH: fprintf (file, ": v850ea architecture"); break;
+    case E_V850E_ARCH:  fprintf (file, _("v850e architecture")); break;
+    case E_V850EA_ARCH: fprintf (file, _("v850ea architecture")); break;
 /* end-sanitize-v850e */
     }
   
@@ -1665,21 +1940,15 @@ v850_elf_section_from_bfd_section (abfd, hdr, sec, retval)
      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;
+    *retval = SHN_V850_SCOMMON;
+  else if (strcmp (bfd_get_section_name (abfd, sec), ".tcommon") == 0)
+    *retval = SHN_V850_TCOMMON;
+  else if (strcmp (bfd_get_section_name (abfd, sec), ".zcommon") == 0)
+    *retval = SHN_V850_ZCOMMON;
+  else
+    return false;
+  
+  return true;
 }
 
 /* Handle the special V850 section numbers that a symbol may use.  */
@@ -1690,8 +1959,36 @@ v850_elf_symbol_processing (abfd, asym)
      asymbol * asym;
 {
   elf_symbol_type * elfsym = (elf_symbol_type *) asym;
+  unsigned short index;
+  
+  index = elfsym->internal_elf_sym.st_shndx;
 
-  switch (elfsym->internal_elf_sym.st_shndx)
+  /* If the section index is an "ordinary" index, then it may
+     refer to a v850 specific section created by the assembler.
+     Check the section's type and change the index it matches.
+     
+     FIXME: Should we alter the st_shndx field as well ?  */
+  
+  if (index < elf_elfheader(abfd)[0].e_shnum)
+    switch (elf_elfsections(abfd)[index]->sh_type)
+      {
+      case SHT_V850_SCOMMON:
+       index = SHN_V850_SCOMMON;
+       break;
+       
+      case SHT_V850_TCOMMON:
+       index = SHN_V850_TCOMMON;
+       break;
+       
+      case SHT_V850_ZCOMMON:
+       index = SHN_V850_ZCOMMON;
+       break;
+       
+      default:
+       break;
+      }
+  
+  switch (index)
     {
     case SHN_V850_SCOMMON:
       if (v850_elf_scom_section.name == NULL)
@@ -1750,7 +2047,7 @@ v850_elf_symbol_processing (abfd, asym)
 }
 
 /* Hook called by the linker routine which adds symbols from an object
-   file.  We must handle the special MIPS section numbers here.  */
+   file.  We must handle the special v850 section numbers here.  */
 
 /*ARGSUSED*/
 static boolean
@@ -1763,7 +2060,34 @@ v850_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
      asection **              secp;
      bfd_vma *                valp;
 {
-  switch (sym->st_shndx)
+  int index = sym->st_shndx;
+  
+  /* If the section index is an "ordinary" index, then it may
+     refer to a v850 specific section created by the assembler.
+     Check the section's type and change the index it matches.
+     
+     FIXME: Should we alter the st_shndx field as well ?  */
+  
+  if (index < elf_elfheader(abfd)[0].e_shnum)
+    switch (elf_elfsections(abfd)[index]->sh_type)
+      {
+      case SHT_V850_SCOMMON:
+       index = SHN_V850_SCOMMON;
+       break;
+       
+      case SHT_V850_TCOMMON:
+       index = SHN_V850_TCOMMON;
+       break;
+       
+      case SHT_V850_ZCOMMON:
+       index = SHN_V850_ZCOMMON;
+       break;
+       
+      default:
+       break;
+      }
+  
+  switch (index)
     {
     case SHN_V850_SCOMMON:
       *secp = bfd_make_section_old_way (abfd, ".scommon");
@@ -1875,7 +2199,7 @@ v850_elf_fake_sections (abfd, hdr, sec)
 #define ELF_MACHINE_CODE                       EM_CYGNUS_V850
 #define ELF_MAXPAGESIZE                                0x1000
        
-#define elf_info_to_howto                      0
+#define elf_info_to_howto                      v850_elf_info_to_howto_rela
 #define elf_info_to_howto_rel                  v850_elf_info_to_howto_rel
 
 #define elf_backend_check_relocs               v850_elf_check_relocs
@@ -1888,6 +2212,11 @@ v850_elf_fake_sections (abfd, hdr, sec)
 #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 elf_backend_gc_mark_hook                v850_elf_gc_mark_hook
+#define elf_backend_gc_sweep_hook               v850_elf_gc_sweep_hook
+
+#define elf_backend_can_gc_sections 1
+
 
 #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
This page took 0.048733 seconds and 4 git commands to generate.