target: consider addressable unit size when reading/writing memory
[deliverable/binutils-gdb.git] / bfd / elf32-msp430.c
index 3a1c0a1c10440654b4abb15ef051fb57a3d5aa3e..edd49f7e4897d7f2b6bcffe0afcedc1ec72974c4 100644 (file)
 #include "elf-bfd.h"
 #include "elf/msp430.h"
 
+static bfd_reloc_status_type
+rl78_sym_diff_handler (bfd * abfd,
+                      arelent * reloc,
+                      asymbol * sym ATTRIBUTE_UNUSED,
+                      void * addr ATTRIBUTE_UNUSED,
+                      asection * input_sec,
+                      bfd * out_bfd ATTRIBUTE_UNUSED,
+                      char ** error_message ATTRIBUTE_UNUSED)
+{
+  bfd_size_type octets;
+  octets = reloc->address * bfd_octets_per_byte (abfd);
+
+  /* Catch the case where bfd_install_relocation would return
+     bfd_reloc_outofrange because the SYM_DIFF reloc is being used in a very
+     small section.  It does not actually matter if this happens because all
+     that SYM_DIFF does is compute a (4-byte) value.  A second reloc then uses
+     this value, and it is that reloc that must fit into the section.
+
+     This happens in eg, gcc/testsuite/gcc.c-torture/compile/labels-3.c.  */
+  if ((octets + bfd_get_reloc_size (reloc->howto))
+      > bfd_get_section_limit_octets (abfd, input_sec))
+    return bfd_reloc_ok;
+  return bfd_reloc_continue;
+}
+
 static reloc_howto_type elf_msp430_howto_table[] =
 {
   HOWTO (R_MSP430_NONE,                /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        3,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield,/* complain_on_overflow */
+        complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MSP430_NONE",       /* name */
         FALSE,                 /* partial_inplace */
@@ -185,7 +210,7 @@ static reloc_howto_type elf_msp430_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
-        NULL,                  /* special handler.  */
+        rl78_sym_diff_handler, /* special handler.  */
         "R_MSP430_SYM_DIFF",   /* name */
         FALSE,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
@@ -197,11 +222,11 @@ static reloc_howto_type elf_msp430x_howto_table[] =
 {
   HOWTO (R_MSP430_NONE,                /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        3,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield,/* complain_on_overflow */
+        complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MSP430_NONE",       /* name */
         FALSE,                 /* partial_inplace */
@@ -488,7 +513,7 @@ static reloc_howto_type elf_msp430x_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
-        NULL,                  /* special handler.  */
+        rl78_sym_diff_handler, /* special handler.  */
         "R_MSP430X_SYM_DIFF",  /* name */
         FALSE,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
@@ -619,7 +644,7 @@ msp430_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED,
     {
       if (r_type >= (unsigned int) R_MSP430x_max)
        {
-         _bfd_error_handler (_("%A: invalid MSP430X reloc number: %d"), abfd, r_type);
+         _bfd_error_handler (_("%B: invalid MSP430X reloc number: %d"), abfd, r_type);
          r_type = 0;
        }
       cache_ptr->howto = elf_msp430x_howto_table + r_type;
@@ -628,7 +653,7 @@ msp430_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED,
 
   if (r_type >= (unsigned int) R_MSP430_max)
     {
-      _bfd_error_handler (_("%A: invalid MSP430 reloc number: %d"), abfd, r_type);
+      _bfd_error_handler (_("%B: invalid MSP430 reloc number: %d"), abfd, r_type);
       r_type = 0;
     }
   cache_ptr->howto = &elf_msp430_howto_table[r_type];
@@ -1596,7 +1621,7 @@ msp430_elf_relax_adjust_locals (bfd * abfd, asection * sec, bfd_vma addr,
       unsigned int sidx = ELF32_R_SYM(irel->r_info);
       Elf_Internal_Sym *lsym = isym + sidx;
 
-      /* Adjust symbols referenced by .sec+0xXX */
+      /* Adjust symbols referenced by .sec+0xXX */
       if (irel->r_addend > addr && irel->r_addend < toaddr
          && sidx < symtab_hdr->sh_info
          && lsym->st_shndx == sec_shndx)
@@ -1656,9 +1681,38 @@ msp430_elf_relax_delete_bytes (bfd * abfd, asection * sec, bfd_vma addr,
   symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
   isym = (Elf_Internal_Sym *) symtab_hdr->contents;
   for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
-    if (isym->st_shndx == sec_shndx
-       && isym->st_value > addr && isym->st_value < toaddr)
-      isym->st_value -= count;
+    {
+      const char * name;
+
+      name = bfd_elf_string_from_elf_section
+       (abfd, symtab_hdr->sh_link, isym->st_name);
+      name = (name == NULL || * name == 0) ? bfd_section_name (abfd, sec) : name;
+
+      if (isym->st_shndx != sec_shndx)
+       continue;
+      
+      if (isym->st_value > addr
+         && (isym->st_value < toaddr
+             /* We also adjust a symbol at the end of the section if its name is
+                on the list below.  These symbols are used for debug info
+                generation and they refer to the end of the current section, not
+                the start of the next section.  */
+             || (isym->st_value == toaddr
+                 && name != NULL
+                 && (CONST_STRNEQ (name, ".Letext")
+                     || CONST_STRNEQ (name, ".LFE")))))
+       {
+         if (isym->st_value < addr + count)
+           isym->st_value = addr;
+         else
+           isym->st_value -= count;
+       }
+      /* Adjust the function symbol's size as well.  */
+      else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC
+              && isym->st_value + isym->st_size > addr
+              && isym->st_value + isym->st_size < toaddr)
+       isym->st_size -= count;
+    }
 
   /* Now adjust the global symbols defined in this section.  */
   symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
@@ -1674,7 +1728,19 @@ msp430_elf_relax_delete_bytes (bfd * abfd, asection * sec, bfd_vma addr,
          && sym_hash->root.u.def.section == sec
          && sym_hash->root.u.def.value > addr
          && sym_hash->root.u.def.value < toaddr)
-       sym_hash->root.u.def.value -= count;
+       {
+         if (sym_hash->root.u.def.value < addr + count)
+           sym_hash->root.u.def.value = addr;
+         else
+           sym_hash->root.u.def.value -= count;
+       }
+      /* Adjust the function symbol's size as well.  */
+      else if (sym_hash->root.type == bfd_link_hash_defined
+              && sym_hash->root.u.def.section == sec
+              && sym_hash->type == STT_FUNC
+              && sym_hash->root.u.def.value + sym_hash->size > addr
+              && sym_hash->root.u.def.value + sym_hash->size < toaddr)
+       sym_hash->size -= count;
     }
 
   return TRUE;
This page took 0.026241 seconds and 4 git commands to generate.